Arithmetic operations between constants

Consider this code;

#define A 5 #define B 3 int difference = A - B; 

Is the "difference" value hard-coded as "2" at compile time or is it computed at runtime?

+6
source share
2 answers

Macros A and B little distracting. It:

 #define A 5 #define B 3 int difference = A - B; 

exactly equivalent to this:

 int difference = 5 - 3; 

therefore, we will discuss the latter.

5 - 3 is a constant expression, which is an expression that "can be evaluated at the time of translation, and not at run time, and, accordingly, can be used anywhere where there can be a constant." It is also an integer constant expression. For example, the case label must be an integer constant expression, so you can write either this:

 switch (foo) { case 2: /* this is a constant */ ... } 

or that:

 switch (foo) { case 5 - 3: /* this is a constant expression */ ... } 

But keep in mind that the definition says that it can be evaluated at the time of translation, and not what it should be. There are some contexts that require constant expressions, and in these contexts the expression must be evaluated at compile time.

But assuming difference declared inside some function, the initializer is not one of these contexts.

Any compiler deserving that you pay for it (even if it is free) will reduce the time 5 - 3 to 2 at compile time and generate code that stores the value 2 in difference . But this was not required. Standard C defines the behavior of programs; he does not indicate how this behavior should be implemented. But it is safe to assume that any compiler that you use will replace 5 - 3 with 2 .

Even if you write:

 int difference = 2; 

the compiler can legitimately generate code that loads the value 5 into the register, subtracts 3 from it, and stores the contents of the register in difference . That would be stupid, but the language standard does not exclude it.

As long as the end result is that the difference is 2 , the language standard does not care how it is done.

On the other hand, if you write:

 switch (foo) { case 5 - 3: /* ... */ case 2: /* ... */ } 

then the compiler must calculate the result so that it can diagnose the error (you cannot have two label labels with the same value.

Finally, if you define a difference in the file area (outside of any function), then the initial value should be constant. But the real difference in this case is not whether 5 - 3 be evaluated at compile time, but whether you are allowed to use a mutable expression.

Reference: the latest draft of the 2011 C standard - N1570 (large PDF); constant expressions are discussed in section 6.6.

+6
source

This is not specified in the standard. He says nothing about possible optimizations (and not in vain. The standard defines semantics, not implementation).

Why not look at the disassembly for your compiler? This will give you the final answer.

...

So let's do it.

Here is the result 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, he simply replaced the appearance of x static value of 2 and pushed it onto the stack to call cout . He did not evaluate expression at runtime.

+5
source

Source: https://habr.com/ru/post/910305/


All Articles