5

In code reviews I ask for option (1) below to be used as it results in a symbol being created (for debugging) whereas (2) and (3) do not appear to do so at least for gcc and icc. However (1) is not a true const and cannot be used on all compilers as an array size. Is there a better option that includes debug symbols and is truly const for C?

Symbols:

gcc f.c -ggdb3 -g ; nm  -a a.out | grep _sym
0000000100000f3c s _symA
0000000100000f3c - 04 0000 STSYM _symA

Code:

static const int symA = 1;  // 1

#define symB 2 // 2

enum { symC = 3 }; // 3

GDB output:

(gdb) p symA
$1 = 1

(gdb) p symB
No symbol "symB" in current context.

(gdb) p symC
No symbol "symC" in current context.

And for completeness, the source:

#include <stdio.h>

static const int symA = 1;

#define symB 2

enum { symC = 3 };

int main (int   argc, char *argv[])
{
    printf("symA %d symB %d symC %d\n", symA, symB, symC);
    return (0);
}
Goblinhack
  • 2,859
  • 1
  • 26
  • 26
  • 2
    You should check out [`static const` vs `#define`](http://stackoverflow.com/questions/1674032/static-const-vs-define-in-c/). I'm surprised that you think that an enumeration symbol is not in the debugging information, though it would not show up as an allocated symbol in the memory map. I strongly recommend `enum`. – Jonathan Leffler Mar 24 '14 at 15:20
  • Updated the example above to include GDB. It does appear only A is present. – Goblinhack Mar 24 '14 at 15:54
  • Curious: using GCC 4.8.2 and GDB 7.7 on an Ubuntu 12.04 derivative and your code, I get: `(gdb) br main` / `Breakpoint 1 at 0x4004df: file gdb.c, line 11.` / `(gdb) r` / `Starting program: /home/jleffler/soq/gdb-test` / `Breakpoint 1, main (argc=1, argv=0x7fffffffe1e8) at gdb.c:11` / `11 printf("symA %d symB %d symC %d\n", symA, symB, symC);` / `(gdb) p symC` / `$1 = symC` / `(gdb) p (int)symC` / `$2 = 3` which shows that this GCC on this platform includes the symbol information for `symC`. I'm not sure what you're using where, but I'm puzzled about the behaviour of your tool chain. – Jonathan Leffler Mar 24 '14 at 16:24
  • Interesting. This is on MacOSX, i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00) – Goblinhack Mar 24 '14 at 18:44
  • I tried a couple of linux builds wit gcc 3.4.6 and 4.8.1. 4.8.1 had the same output as you (works for enum). The older version had what I reported. So seems that this is not linux/macos dependent, but rather something that was fixed in a gcc release. So I think for newer code I would tend towards enum. – Goblinhack Mar 24 '14 at 18:52

2 Answers2

2

The -ggdb3 option should be giving you macro debugging information. But this is a different kind of debugging information (it has to be different - it tells the debugger how to expand the macro, possibly including arguments and the # and ## operators) so you can't see it with nm.

If your goal is to have something that shows up in nm, then I guess you can't use a macro. But that's a silly goal; you should want to have something that actually works in a debugger, right? Try print symC in gdb and see if it works.

Since macros can be redefined, gdb requires the program to be stopped at a location where the macro existed so it can find the correct definition. In this program:

#include <stdio.h>
int main(void)
{
  #define X 1
  printf("%d\n", X);
  #undef X
  printf("---\n");
  #define X 2
  printf("%d\n", X);
}

If you break on the first printf and print X you'll get the 1; next to the second printf and gdb will tell you that there is no X; next again and it will show the 2.

Also the gdb command info macro foo can be useful, if foo is a macro that takes arguments and you want to see its definition rather than expand it with a specific set of arguments. And if a macro expands to something that's not an expression, gdb can't print it so info macro is the only thing you can do with it.

For better inspection of the raw debugging information, try objdump -W instead of nm.

1

However (1) is not a true const and cannot be used on all compilers as an array size.

This can be used as array size on all compilers that support C99 and latter (gcc, clang). For others (like MSVC) you have only the last two options.
Using option 3 is preferred 2. enums are different from #define constants. You can use them for debugging. You can use enum constants as l-value as well unlike #define constants.

haccks
  • 104,019
  • 25
  • 176
  • 264
  • MSVC most definitely supports C99. Is there a bug that prevents it from allowing `static const` array sizes? (Edit: Just checked... it works fine in VC++ in both 2012 and 2010.) – TypeIA Mar 24 '14 at 14:34
  • @dvnrrs; No. It does not. You can test by compiling a simple program which uses variable length arrays on MSVC. – haccks Mar 24 '14 at 14:35
  • 1
    @dvnrrs Visual studio does support C99 but [I don't think it supports VLA](http://stackoverflow.com/questions/18521398/which-compiler-should-i-trust/18521417#18521417). – Shafik Yaghmour Mar 24 '14 at 14:36
  • I stand corrected, my apologies. They have apparently (in their own words) "cherry-picked" only some C99 features and don't support the full standard. I always assumed it was full support since it does support everything from C99 I've ever tried to use. In any case, `static const` array sizes **are** allowed, so this answer still needs updating (all 3 options are viable in MSVC). – TypeIA Mar 24 '14 at 14:38
  • @dvnrrs; Does MSVC allow mixed type declaration? – haccks Mar 24 '14 at 14:41
  • @haccks Yes it does (tested back to 2005, but if memory serves even VC6 did.) – TypeIA Mar 24 '14 at 14:43
  • @dvnrrs; Well you should read [this](http://stackoverflow.com/q/146381/2455888). And also [this](http://msdn.microsoft.com/en-us/library/02y9a5ye.aspx) – haccks Mar 24 '14 at 14:46
  • `printf("%ld\n", __STDC_VERSION__);`//if C99 then 199901L – BLUEPIXY Mar 24 '14 at 15:07
  • @dvnrrs see [Compiler Error C2057](http://msdn.microsoft.com/en-us/library/eff825eh.aspx) – BLUEPIXY Mar 24 '14 at 16:16