C标准的哪个部分允许编译此代码?

Jon*_*ler 14 c

我修错了一些代码并且编译器警告(合法地)该函数dynscat()未被声明 - 其他人对可接受的编码标准的想法 - 因此我追踪了函数定义的位置(足够简单)以及哪个头部声明了它(无) ; Grrr!).但我期望找到结构定义的细节是extern宣布以下内容所必需的qqparse_val:

extern struct t_dynstr qqparse_val;

extern void dynscat(struct t_dynstr *s, char *p);
extern void qqcat(char *s);

void qqcat(char *s)
{
    dynscat(&qqparse_val, s);
    if (*s == ',')
        dynscat(&qqparse_val, "$");
}
Run Code Online (Sandbox Code Playgroud)

qqcat()原始代码中的函数是静态的; extern声明会对此代码片段的编译器警告进行平息.该dynscat()函数声明缺少完全; 再次,添加它平息警告.

通过显示的代码片段,很明显只使用了变量的地址,因此在一个层次上有意义的是,结构的细节未知是无关紧要的.如果是变量extern struct t_dynstr *p_parseval;,你就不会看到这个问题; 这将是100%预期.如果代码需要访问结构的内部,那么将需要结构定义.但我总是期望如果你声明变量是一个结构(而不​​是结构的指针),编译器会想知道结构的大小 - 但显然不是.

我曾经试图挑起GCC抱怨,但事实并非如此,即使是GCC 4.7.1:

gcc-4.7.1 -c -Wall -Wextra -std=c89 -pedantic surprise.c
Run Code Online (Sandbox Code Playgroud)

该代码已经在AIX,HP-UX,Solaris,Linux上进行了十年的编译,因此它不被GCC特定的接受.

这是C标准允许的(主要是C99或C11,但C89也会这样做)?哪个部分?或者我只是碰到了一个奇怪的球案,它适用于所有移植到它的机器,但是没有被标准正式批准?

Fle*_*exo 15

你所拥有的是一种不完整的类型(ISO/IEC 9899:1999和2011 - 所有这些参考文献都是相同的 - §6.2.522):

未知内容的结构或联合类型(如§6.7.2.3中所述)是不完整类型.

不完整的类型仍然可以是左值:

§6.3.2.11(左值,数组和函数指示符)

左值是具有对象类型或除void之外的不完整类型的表达式; ...

因此,它就像任何其他&具有左值的一元一样.

  • 我很惊讶这不是公认的答案,因为问题包括"C标准的哪一部分......"和"哪部分?".接受的答案没有提到哪个部分或哪个部分. (6认同)

Jen*_*ens 8

看起来像一个采用不完整类型的对象的地址的情况.

使用指向不完整类型的指针是完全理智的,你每次使用指向无效指针时都会这样做(但是没有人告诉过你:-)

另一种情况是你宣布类似的东西

extern char a[];
Run Code Online (Sandbox Code Playgroud)

你可以分配给a哪些元素并不奇怪吧?尽管如此,它是一个不完整的类型,只要你将这样的标识符作为a的操作数,编译器就会告诉你sizeof.

  • 为什么恐怖?您可以使用不完整的类型结构,例如创建"不透明类型",隐藏内部结构,例如`struct FILE`中的内容.所有访问都是通过函数获取指向不完整类型的函数进行的,这是标准IO库的作用. (2认同)

Jen*_*edt 5

你的路线

extern struct t_dynstr qqparse_val;
Run Code Online (Sandbox Code Playgroud)

是对象的外部声明,而不是定义.作为外部对象,它"具有联系"即外部联系.

标准说:

如果声明对象的标识符没有链接,则对象的类型应在其声明符的末尾完成,...

这意味着如果它具有链接,则类型可能是不完整的.所以&qqparse_val事后没有问题.sizeof(qqparse_val)由于对象类型不完整,您将无法做到的.