没有初始化的C字符串没有警告

Max*_*nft 24 c global-variables definition header-files forward-declaration

我目前想知道为什么在编译/链接小型C程序时我没有从GCC收到错误.

我在version.h以下字符串中声明:

const char* const VERSION;
Run Code Online (Sandbox Code Playgroud)

version.c我已设置变量的初始化:

const char* const VERSION = "0.8 rev 213";
Run Code Online (Sandbox Code Playgroud)

没问题.我可以在程序的其余部分使用该字符串.

如果缺少c文件,则在编译/链接期间不会发生错误,但是当程序尝试访问变量时,程序会失败并且SIGSEGV(当然).

我设置变量的方法是VERSION正确的还是有更好的方法?或者在编译/链接期间是否有机会出错?

n. *_* m. 31

您已在标头中定义(而不仅仅是声明)变量.

如果您从多个源文件中包含此标头,则行为未定义.这是标准的相关引用:

J.2未定义的行为

...

使用具有外部链接的标识符,但是在程序中,不存在标识符的正好一个外部定义,或者不使用标识符,并且标识符存在多个外部定义.

...

您依赖于GCC特定的(在许多编译器中通常是常见的,但仍然是非标准的)行为,这是合并重复的暂定数据定义.请参阅帮助-fcommon-fno-commonGCC编译标志.并非所有编译器都以这种方式运行.从历史上看,这是链接器的常见行为,因为这是Fortran在C之前的工作方式.

假设这种语言扩展,其中一个定义(具有显式初始化器的定义)初始化变量以指向您的字符串文字.但是如果省略这个定义,它将保持零初始化.也就是说,它将是一个常量空指针.不是很有用.

长话短说,永远不要那么做.要在标头中声明(但不定义)全局变量,请使用extern.如果你这样做,并尝试在别处省略一个定义,你可能会收到一个链接器错误(虽然标准不需要诊断这个违规,所有已知的实现产生一个).


PSk*_*cik 15

你的例子是有效的,因为C(但不是C++)的Fortran启发(错误)特征称为暂定定义(6.9.2p2),它通常但非标准地扩展到多个文件.

暂定定义是extern没有初始化器和没有初始化器的变量声明.在通常的实现中(双关语),暂定定义创建一种称为common符号的特殊符号.在链接期间,在存在同名的常规符号的情况下,其他常见符号将成为常规符号的引用,这意味着VERSION由于包含而在您的翻译单元中创建的所有空s将成为对常规符号的引用const char* const VERSION = "0.8 rev 213";.如果没有这样的常规符号,则公共符号将合并为单个零初始化变量.

我不知道如何使用C编译器对此进行警告.

这个

const char* const VERSION;
const char* const VERSION = "0.8 rev 213";
Run Code Online (Sandbox Code Playgroud)

似乎与gcc一起工作无论我尝试过什么(g++不会接受它 - C++没有暂定的定义功能,它不喜欢未明确初始化的const变量).但你可以编译-fno-common(这是一个相当"常见"(强烈推荐)非标准选项(gcc,clang和tcc都有它))然后如果非初始化和初始化的extern-你会得到一个链接器错误 -较少的声明在不同的翻译单元中.

例:

VC:

const char * VERSION;
Run Code Online (Sandbox Code Playgroud)

main.c中

const char* VERSION;
int main(){}
Run Code Online (Sandbox Code Playgroud)

编译和链接:

gcc main.c v.c #no error because of tentative definitions
g++ main.c v.c #linker error because C++ doesn't have tentative definitions
gcc main.c v.c -fno-common #linker error because tentative defs. are disabled
Run Code Online (Sandbox Code Playgroud)

(const为了C++示例,我在示例中删除了第二个--C++另外使const全局变量静态或类似的东西只会使临时定义功能的演示变得复杂.)

禁用暂定定义或使用C++时,标头中的所有变量声明都应包含extern在其中

version.h中:

extern const char* const VERSION;
Run Code Online (Sandbox Code Playgroud)

并且每个全局应该只有一个定义,并且该定义应该有一个初始化器或者没有extern(如果你应用于extern初始化变量,一些编译器会发出警告).

version.c:

#include "version.h" //optional; for type checking
const char* const VERSION = "0.8 rev 213";
Run Code Online (Sandbox Code Playgroud)


Ach*_*hal 6

version.h你应该宣布VERSIONextern 一样

extern const char* const VERSION;
Run Code Online (Sandbox Code Playgroud)

version.c你应该定义外部变量之类的

const char* const VERSION = "0.8 rev 213";
Run Code Online (Sandbox Code Playgroud)

编辑: -您还需要确保只有一个源文件定义了变量,  VERSION 而其他源文件声明了它  extern,您可以通过在源文件中定义它VERSION.c 并将  extern 声明放在头文件中来完成VERSION.h.