开发者

Symbolic constants in C

Considering the symbolic constants using macros,enumeration constants and const objects. In macros scope is global and cannot be limited to local scope which is a major disadvantage. Enumera开发者_如何学Ction constants cannot be used in situations other than the integers,Enumeration constants cannot be represented in float or long. Const objects can have local scope,can be represented in different datatypes. But in c declaring a "int const a" or "const int a" makes the value constant and int buffer[a] is not permitted in c.. But in c++ int buffer[a] is permitted as it takes the "const a" as a compiler constant only.

Despite the disadvantages mentioned most of them generally prefer defining symbolic constants as enumeration constants rather than as const objects.

I could not understand the below statement telling that const objects cause performance penalty.How does it cause.Please help me understand..

The problem with const objects is that they may incur a performance penalty, which enumeration constants avoid.


An object declared with const is not a constant (more precisely, its name is not a constant expression). The const keyword doesn't mean "constant", it means "read-only". So given:

const int answer = 42;
printf("The answer is %d\n", answer);

in principal the evaluation of the printf call needs to fetch the value of answer from storage before passing it to the printf function.

But in fact, any compiler worth what you pay for it (even if it's free) will optimize the reference to answer, so that the printf call results in the same machine code as

printf("The answer is %d\n", 42);

(gcc does this with -O1 or better. If you don't specify -O..., then the code actually fetches the value of the object - but then if you don't ask for optimization, you're telling the compiler you don't care much about performance.)

(A really clever compiler could generate code equivalent to

puts("The answer is 42");

.)

The real difference is that the name answer cannot be used in contexts that require a constant expression. For example, case answer: ... would be legal in C++, but is illegal in C.

Note that int arr[answer]; is actually legal, at least in C99, which allows variable-length arrays. It would be equally legal if you had written

const int answer = rand() % 100 + 1;

But VLAs can only have automatic storage duration, so they cannot be declared at file scope or with the static keyword.

As for the enum trick:

enum { answer = 42; }

that does make answer a constant expression, but it's restricted to values of type int (C enumeration constants are always of type int). Some might argue that this is an abuse of the enum feature. It is, but I don't let that bother me.

So there might be a performance penalty for const int answer = 42; as opposed to #define answer 42, but in practice it's just going to restrict the contexts in which you can use it.


You are seeing some old information that was true at some point in the past, but is no longer completely accurate. Unfortunately, there are a host of differences between the following simple ways to define constants:

  1. static const int CONSTANT = 10;

    Drawbacks: It can't be used in a "constant expression" so you won't be able to use it for array sizes for arrays with static storage duration, or cases in switch statements.

  2. enum { CONSTANT = 10 };

    Drawbacks: It can't have type other than int. For example, 1U << 31 is not strictly portable to systems with 32-bit int and 1ULL << 48 will probably break on many systems. Does not have an address.

  3. #define CONSTANT 10

    Drawbacks: It interacts poorly with the debugger and it interferes with normal C scoping rules. Does not have an address.

In a modern compiler, all three of these should have exactly the same runtime performance properties. So, don't worry about performance.

Note: This doesn't apply to the following:

const int CONSTANT = 10;

This will probably get an address in memory whether you use it or not, unless you have a very fancy linker with link-time optimization (most people don't).


I think I understand the line you quoted. Consider this: enumeration constants are immediate values in the resulting machine code, and these are usually faster to read than values that must actually be read from memory.

const int a = 7;

is actually an int that is stored somewhere and must be read from there. In e.g. x86 machine code, it is read as:

MOV  EAX,[a]

and that is a real memory access. OTOH, an enum like

enum X { a=7, b, c };

is read as immediate value

MOV  EAX,7

which is usually faster, also in other CPUs.

I guess that is what was meant with the line you quoted.

Of course, a good compiler can actually infer that the value of const int a = 7; never changes, so it could take the value an emit machine code that actually does MOV EAX,7, but there is no guarantee for that. Enums are immediate values, so they will be guaranteed to be used like that.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜