Consider this code;
#define A 5
#define B 3
int difference = A - B;
does value of "difference" is hardcoded as "2" in compile time, or does it get calculated on runtime?
The A
and B
macros are a bit of a distraction. This:
#define A 5
#define B 3
int difference = A - B;
is exactly equivalent to this:
int difference = 5 - 3;
so let's discuss the latter.
5 - 3
is a constant expression, which is an expression that "can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be". It's also an *integer constant expression". For example, a case label must be an integer constant expression, so you could write either this:
switch (foo) {
case 2: /* this is a constant */
...
}
or this:
switch (foo) {
case 5 - 3: /* this is a constant expression */
...
}
But note that the definition says that it can be evaluated during translation, not that it must be. There are some contexts that require constant expressions, and in those contexts the expression must be evaluated at compile time.
But assuming that difference
is declared inside some function, the initializer is not one of those contexts.
Any compiler worth what you pay for it (even if it's free) will reduce 5 - 3
to 2
at compile time, and generate code that stores the value 2
in difference
. But it's not required to do so. The C standard specifies the behavior of programs; it doesn't specify how that behavior must be implemented. But it's safe to assume that whatever compiler you're using will replace 5 - 3
by 2
.
Even if you write:
int difference = 2;
a compiler could legally generate code that loads the value 5
into a register, subtracts 3
from it, and stores the contents of the register into difference
. That would be a silly thing to do, but the language standard doesn't exclude it.
As long as the final result is that difference
has the value 2
, the language standard doesn't care how it's done.
On the other hand, if you write:
switch (foo) {
case 5 - 3: /* ... */
case 2: /* ... */
}
then the compiler must compute the result so it can diagnose the error (you can't have two case labels with the same value.
Finally, if you define difference
at file scope (outside any function), then the initial value does have to be constant. But the real distinction in that case is not whether 5 - 3
will be evaluated at compile time, it's whether you're allowed to use a non-constant expression.
Reference: The latest draft of the 2011 C standard is N1570 (large PDF); constant expressions are discussed in section 6.6.
The standard does not specify this sort of thing. It says nothing about potential optimizations like this (and for good reason. A standard defines semantics, not implementation).
Why not look at the disassembly for your compiler? That will give you a definitive answer.
...
So let's do that.
Here is the output from VC++ 10:
#include <iostream>
#define A 5
#define B 3
int main() {
int x = A - B;
std::cout << x; // make sure the compiler doesn't toss it away
010A1000 mov ecx,dword ptr [__imp_std::cout (10A2048h)]
010A1006 push 2
010A1008 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (10A2044h)]
return 0;
010A100E xor eax,eax
As you can see, it just replaced the occurrence of x
with a static value of 2 and pushed it onto the stack for the call to cout
. It did not evaluate the expression at runtime.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With