繁体   English   中英

外部变量原型:数组不等于 null 指针的比较始终为真

[英]extern variable prototype: comparison of array not equal to a null pointer is always true

在清理旧程序时 GCC 返回了一个我无法理解的警告。 这是一个片段:

#include <stdio.h>
#include <stdint.h>

extern int *foo[];

int main(void) {
    if (foo != NULL)
        printf("Foo is not null\n");
    return 0;
}
$ gcc -Wall main.c
main.c: In function 'main':
main.c:7:17: warning: the comparison will always evaluate as 'true' for the address of 'foo' will never be NULL [-Waddress]
    7 |         if (foo != NULL)
      |                 ^~
main.c:4:13: note: 'foo' declared here
    4 | extern int *foo[];
      |      

然后我尝试将原型更改为extern int **foo; :

$ gcc -Wall main.c
/usr/bin/ld: /tmp/cciux1Df.o: warning: relocation against `foo' in read-only section `.text'
  1. 如这里所示,如果没有初始化,它们应该被认为是相同的。 为什么**foo (理所当然地)无法编译为未定义的引用,而 GCC 使用*foo[]成功编译?

  2. relocation against 'foo' in read-only section '.text'作为警告的真正含义是什么?

谢谢。

编译器试图告诉你这个语句

if (foo != NULL)

没有意义,因为数组总是占用 memory 而你声明了一个数组

extern int *foo[]; .

在 if 语句中,数组指示符foo被隐式转换为int **类型的指针,指向数组的第一个元素(即数组占用的范围为 memory)。 所以它不能等于NULL

请注意,您应该在这个或其他翻译单元的某处定义数组。 否则 linker 会发出未定义数组的错误。 因为上面数组的声明不是它的定义也不是它的暂定。

此测试可能用作弱链接的一种形式。 在某些情况下,该程序可能与数组的定义相关联,而在其他情况下,linker 是为符号分配零值(linker 符号的零值对应于 C 中数组的零地址) .

因此行为不会由 C 标准定义,但是这段旧代码可能没有被编写为符合标准的代码,并且这可能与当时使用的编译器和 linker 一起工作。

如这里所示,如果没有初始化,它们应该被认为是相同的。

这是数组参数上下文中的 C++ 问题。 您不应将其用于提及此问题。

为什么**foo (理所当然地)无法编译为未定义的引用,而 GCC 使用*foo[]成功编译?

extern int *foo[]; , foo foo != NULL中的 foo 被转换为它的第一个元素的地址,编译器假设它永远不会是 null,所以它将foo != NULL优化为“true”。 因此,生成的 object 代码不包含对foo的任何引用,因为优化将其删除。

extern int **foo; foo foo != NULL中的 foo 需要获取存储在foo中的值来测试它是否为 null 指针,因此生成的 object 代码尝试从foo加载数据。 然后 linker 无法满足对foo的引用,因此它会抱怨。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM