C 如何禁止在编译时使用全局变量

C 如何禁止在编译时使用全局变量,c,gcc,compiler-construction,C,Gcc,Compiler Construction,有没有办法禁止使用全局变量 我希望GCC在定义全局变量时在编译时生成一个错误 我们有一个应该在每个线程上运行的代码,并且只允许使用堆栈(这是线程安全的) 有没有办法强制执行 某些GCC标志或其他方式来验证它?GCC中没有此类功能。一些解决方法是在构建过程中加入一个可以检测全局变量的静态分析工具。尽管编译不会失败,但至少会以某种方式警告您。我可以看到PC Lint(www.gimpel.com)有一个 非常量非易失性全局变量,定位这些变量可以帮助多线程应用程序检测不可重入的情况 可能其他工具也包含

有没有办法禁止使用全局变量

我希望GCC在定义全局变量时在编译时生成一个错误

我们有一个应该在每个线程上运行的代码,并且只允许使用堆栈(这是线程安全的)

有没有办法强制执行


某些GCC标志或其他方式来验证它?

GCC中没有此类功能。一些解决方法是在构建过程中加入一个可以检测全局变量的静态分析工具。尽管编译不会失败,但至少会以某种方式警告您。我可以看到PC Lint(www.gimpel.com)有一个

非常量非易失性全局变量,定位这些变量可以帮助多线程应用程序检测不可重入的情况

可能其他工具也包含类似的功能。

我将使用它从源代码中提取符号,然后使用(perl或python)脚本搜索输出中的全局变量

例如,以下行将告诉您C soucre文件
hello.C
是否包含全局变量:

ctags -f- hello.c | perl -ne"@a=split(/\t/, $_); if ($a[3] eq qq(v)){ print qq(Has global variables.); exit 0; }"

一种方法是生成链接器映射文件(例如,将选项-Wl,-map,program.map传递到gcc),并检查.data.bss输出部分,以查看您希望在不使用全局变量的情况下运行的目标文件的任何贡献

例如,如果我的源文件hello.c具有:

static int gTable[100];
链接器映射文件将包含如下内容:

.bss            0x0000000000600940      0x1b0
 *(.dynbss)
 .dynbss        0x0000000000000000        0x0 /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o
 *(.bss .bss.* .gnu.linkonce.b.*)
 .bss           0x0000000000600940        0x0 /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o
 .bss           0x0000000000600940        0x0 /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crti.o
 .bss           0x0000000000600940        0x1 /usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o
 *fill*         0x0000000000600941       0x1f 00
 .bss           0x0000000000600960      0x190 hello.o

您可以看到,hello.o正在向.bss部分贡献0x190(400)字节。我曾使用Python脚本解析链接映射文件的方法,为嵌入式项目生成代码大小和RAM使用指标,在过去取得了一定的成功;链接器的文本输出格式非常稳定。

从我看来不太稳定,我认为这在目前是不可能的。添加它并不难,其他人可能会感兴趣,因此我建议您将其重新表述为一个功能请求,并将其发送到邮件列表
gcc-help@gcc.gnu.org
。什么是全局变量?函数中的静态变量是全局变量吗?答:没有,但它属于你的“定义”之一。更进一步,如果我有一个指向堆分配内存块的堆栈指针,那么它是指向一个“全局”变量的指针还是全局变量本身?编译器究竟是如何跟踪这些事情的?嗯,通过
malloc
分配的任何东西也不在堆栈上,所以。。。但说真的,全局变量在C语言中是合法的,尽管经常有争议(出于正当理由和宗教原因),但它们仍然经常有用。我怀疑编译器制造商是否会在这样一个关键特性上实现一个“特性”来破坏编译器的语言遵从性。这就像不允许使用
float
const char*
。为什么不使用全局变量呢?实际上,很难“意外”声明一个,因此您不需要编译器的任何帮助。我正在考虑使用nm或objdump扫描全局变量并打印一条警告,这样会更有效,看起来更容易。与静态分析解决方案类似,您将需要从运行库中筛选出全局变量。编译本身可能不会失败,但此检查可以合并到Makefile中,从而导致生成的编译步骤失败。或者,可以编写一个
fake_gcc
包装器脚本,调用真正的编译器,然后进行检查;这样,您可以使编译看起来失败。使用链接器脚本,您还可以将
.data
节的存在变成一个错误——您可以将它们映射到一个零长度的输出区域。+1这个答案和Simon的评论是在您的构建系统中强制执行非全局规则的正确成分。@SimonRichter您能提供一个关于如何映射/限制bss/数据段大小的示例吗使用链接器脚本?变量1:
断言(SIZEOF(.data))==0,“不允许全局数据”)
变量2:
内存{NONE:ORIGIN=0,LENGTH=0}
,后跟
.data{…}>NONE