C语言中的常量初始化器和调试符号

5
在代码审查中,我要求使用选项(1),因为它会创建一个符号(用于调试),而选项(2)和(3)似乎在gcc和icc中不会这样做。但是(1)并不是真正的const,不能在所有编译器上作为数组大小使用。有没有更好的选项,既包括调试符号又真正地是C中的const?
符号:
gcc f.c -ggdb3 -g ; nm  -a a.out | grep _sym
0000000100000f3c s _symA
0000000100000f3c - 04 0000 STSYM _symA

代码:

static const int symA = 1;  // 1

#define symB 2 // 2

enum { symC = 3 }; // 3

GDB 输出:

(gdb) p symA
$1 = 1

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

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

为了完整起见,这里提供原始资料:

#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);
}

2
你应该查看static const vs #define。我很惊讶你认为枚举符号不在调试信息中,尽管它不会显示为内存映射中分配的符号。我强烈推荐使用enum - Jonathan Leffler
已更新上面的示例以包括GDB。似乎只有A存在。 - Goblinhack
好奇:在Ubuntu 12.04的衍生版本上使用GCC 4.8.2和GDB 7.7以及您的代码,我得到以下结果: (gdb) br main 在文件gdb.c的第11行设置断点1。 (gdb) r 正在启动程序:/home/jleffler/soq/gdb-test 在gdb.c的第11行,main函数 (argc=1, argv=0x7fffffffe1e8)被中断。 11 printf("symA %d symB %d symC %d\n", symA, symB, symC); (gdb) p symC $1 = symC (gdb) p (int)symC $2 = 3 这表明在此平台上的GCC包含了symC的符号信息。我不确定您使用的是什么工具链,但对于您的工具链的行为感到困惑。 - Jonathan Leffler
有趣。这是在MacOSX上,i686-apple-darwin11-llvm-gcc-4.2(GCC)4.2.1(基于Apple Inc.构建5658)(LLVM构建2336.1.00)。 - Goblinhack
我尝试了几个带有gcc 3.4.6和4.8.1的Linux版本。 4.8.1与您的输出相同(对枚举有效)。旧版本具有我报告的问题。因此,似乎这不是依赖于Linux / macOS,而是在gcc发布中修复的问题。因此,我认为对于更新的代码,我会倾向于使用枚举。 - Goblinhack
2个回答

2
-ggdb3选项应该提供给您宏调试信息。但这是一种不同类型的调试信息(必须是不同的——它告诉调试器如何扩展宏,可能包括参数和###运算符),因此您不能使用nm查看它。
如果您的目标是有些东西显示在nm中,那么我想您不能使用宏。但这是一个愚蠢的目标;您应该希望有一些实际上在调试器中起作用的东西,对吧?尝试在gdb中输入print symC,看看它是否有效。
由于宏可以重新定义,gdb要求程序停在存在宏的位置,以便找到正确的定义。在这个程序中:
#include <stdio.h>
int main(void)
{
  #define X 1
  printf("%d\n", X);
  #undef X
  printf("---\n");
  #define X 2
  printf("%d\n", X);
}

如果您在第一个printfprint X处中断,您将得到1;继续使用next到第二个printfgdb会告诉您没有X;再用next,它将显示2。
此外,gdb命令info macro foo可能很有用,如果foo是一个带参数的宏,您想查看其定义而不是使用特定的参数集进行扩展。如果一个宏扩展为不是表达式的东西,gdb无法print它,所以info macro是您唯一能做的事情。
为了更好地检查原始调试信息,请尝试使用objdump -W而不是nm

1
然而,(1)不是真正的常量,不能在所有编译器上用作数组大小。
所有支持C99及其后版本(如gcc、clang)的编译器都可以使用此选项作为数组大小。对于其他编译器(如MSVC),您只能选择最后两个选项。使用选项3优于选项2。枚举与#define常量不同。您可以将它们用于调试。您也可以像l-value一样使用枚举常量,而不像#define常量。

MSVC 绝对支持 C99。是否存在一个导致其不允许 static const 数组大小的 bug?(编辑:刚刚检查过了...在 VC++ 2012 和 2010 中都可以正常工作。) - TypeIA
1
@dvnrrs Visual Studio确实支持C99,但是我认为它不支持VLA - Shafik Yaghmour
我承认错误,向您道歉。根据他们自己的说法,他们显然只“挑选了”一些C99功能,并不支持完整的标准。我一直以为它是完全支持的,因为它支持我尝试使用的C99中的所有内容。无论如何,static const数组大小是允许的,因此这个答案仍然需要更新(在MSVC中,所有3个选项都是可行的)。 - TypeIA
@dvnrrs; MSVC允许混合类型声明吗? - haccks
printf("%ld\n", STDC_VERSION); //如果是C99,则为199901L - BLUEPIXY
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接