4

There might be any because of inlining of #define statements.

I understand that answer may be compiler dependent, lets asume GCC then.

There already are similar questions about C and about C++, but they are more about usage aspects.

Community
  • 1
  • 1
user
  • 23,260
  • 9
  • 113
  • 101
  • Give a sample of which kind of values you're asking about. Since you're mentioning `enum`, integer numeric constants I'd guess? – πάντα ῥεῖ Jan 23 '14 at 17:33
  • @πάνταῥεῖ I'm asking in general - about all possible kinds of constants: numbers, string literals, arrays... – user Jan 23 '14 at 17:48
  • 3
    So the take away message is don't use #define to define integral constants in "modern" C++. Use static const if it really is a number. Use enum if it really is an enumerable value. Don't worry about performance and memory usage: Trust your compiler, unless it's REALLY, REALLY critical, in which case trust your compiler, but check to be sure. – Dale Wilson Jan 23 '14 at 17:55

2 Answers2

6

The compiler would treat them the same given basic optimization.
It's fairly easy to check - consider the following c code :

#define a 1
static const int b = 2;
typedef enum {FOUR = 4} enum_t;

int main() {

    enum_t c = FOUR;

    printf("%d\n",a);
    printf("%d\n",b);
    printf("%d\n",c);

    return 0;
}

compiled with gcc -O3:

0000000000400410 <main>:
  400410:       48 83 ec 08             sub    $0x8,%rsp
  400414:       be 01 00 00 00          mov    $0x1,%esi
  400419:       bf 2c 06 40 00          mov    $0x40062c,%edi
  40041e:       31 c0                   xor    %eax,%eax
  400420:       e8 cb ff ff ff          callq  4003f0 <printf@plt>
  400425:       be 02 00 00 00          mov    $0x2,%esi
  40042a:       bf 2c 06 40 00          mov    $0x40062c,%edi
  40042f:       31 c0                   xor    %eax,%eax
  400431:       e8 ba ff ff ff          callq  4003f0 <printf@plt>
  400436:       be 04 00 00 00          mov    $0x4,%esi
  40043b:       bf 2c 06 40 00          mov    $0x40062c,%edi
  400440:       31 c0                   xor    %eax,%eax
  400442:       e8 a9 ff ff ff          callq  4003f0 <printf@plt>

Absolutely identical assembly code, hence - the exact same performance and memory usage.

Edit: As Damon stated in the comments, there may be some corner cases such as complicated non literals, but that goes a bit beyond the question.

Leeor
  • 19,260
  • 5
  • 56
  • 87
  • 3
    Interesting choice of capitalization: a macro with lower case and an enum in all upper case :) – David Rodríguez - dribeas Jan 23 '14 at 17:40
  • Thanks for the answer, but wouldn't assembly representation change if there will be multiple usages of those constants? – user Jan 23 '14 at 17:50
  • 1
    @user3075942: There will be more code, but if you only use the *value*, the compiler is going to replace it at the place of call. Why would 1 or 100 uses of the variable change? – David Rodríguez - dribeas Jan 23 '14 at 18:09
  • @DavidRodríguez-dribeas, didn't even notice that, what's becoming of me... :) – Leeor Jan 23 '14 at 18:17
  • @DavidRodríguez-dribeas If there are simple ints then I agree, but what about other constants such as string literals and arrays? – user Jan 23 '14 at 18:19
  • @user3075942: Since the question mentions `enum` I imagined that you cared about places where you can actually use `enum`. For string literals, it will be roughly the same, have not looked at the assembly, but I would not expect a difference. String literals cannot be embedded into the instruction so it must be at least one dereference away. Arrays cannot be in `#define`'s either so there is little left for comparison – David Rodríguez - dribeas Jan 23 '14 at 18:22
  • @user3075942, in fact, the enum case is a little different as i'm using a variable that can (in theory) get changed. That doesn't prevent the compiler from optimizing it away and assigning the constant value directly as the argument to the print. – Leeor Jan 23 '14 at 18:23
  • 1
    As for string literals - you'll find it's more complicated to compare this case with `enum`, but that doesn't change the fundamental truth - the compiler treats all these as values, and can optimize any type of temporary storage you might think they're holding. As such, there's no sense for it to handle one kind of constant any different than another (not to mention that `#define` is not even seen by the compiler) – Leeor Jan 23 '14 at 18:24
  • 3
    Unluckily, "identical" is not true for _many_ non-integer-literal cases. For example, you might expect a `static const&` being trivially optimizable as well, but it isn't. E.g. `struct foo{int bar;}; static const& bar_ref = foo.bar;` has definitely more overhead than `#define bar_ref foo.bar`. (Yes, there are actually situations where you need such an abomination. Don't ask.) – Damon Jan 23 '14 at 18:37
  • As for string literals, they will be also [optimized](http://stackoverflow.com/questions/11399682/c-optimisation-of-string-literals) in any case. – user Jan 24 '14 at 08:11
3

When used as a constant expression there will be no difference in performance. If used as an lvalue, the static const will need to be defined (memory) and accessed (cpu).

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489