为什么该语句在gcc中产生链接器错误? [英] Why is this statement producing a linker error with gcc?

查看:74
本文介绍了为什么该语句在gcc中产生链接器错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一段非常琐碎的C代码:

I have this extremely trivial piece of C code:

static int arr[];
int main(void) {
    *arr = 4;
    return 0;
}

我知道第一条语句是非法的(我已经声明了具有静态存储持续时间和文件链接但没有指定大小的文件范围数组),但是为什么会导致链接器错误? :

I understand that the first statement is illegal (I've declared a file-scope array with static storage duration and file linkeage but no specified size), but why is it resulting in a linker error? :

/usr/bin/ld: /tmp/cch9lPwA.o: in function `main':
unit.c:(.text+0xd): undefined reference to `arr'
collect2: error: ld returned 1 exit status

编译器难道不能在链接器之前捕获到这一点?

Shouldn't the compiler be able to catch this before the linker?

让我感到奇怪的是,如果我省略了static存储类,则编译器会简单地假设数组的长度为1,并且不会产生任何错误:

It is also strange to me that, if I omit the static storage class, the compiler simply assumes array is of length 1 and produces no error beyond that:

int arr[];
int main(void) {
    *arr = 4;
    return 0;
}

结果:

unit.c:5:5: warning: array 'arr' assumed to have one element
 int arr[];

为什么在这里省略存储类会导致不同的行为,为什么第一段代码会产生链接器错误?谢谢.

Why does omitting the storage class result in different behavior here and why does the first piece of code produce a linker error? Thanks.

推荐答案

空数组static int arr[];和零长度数组static int arr[0];

Empty arrays static int arr[]; and zero-length arrays static int arr[0]; were gcc non-standard extensions.

这些扩展的目的是作为对旧的结构黑客"的修复.早在C90年代,人们就编写了这样的代码:

The intention of these extensions were to act as a fix for the old "struct hack". Back in the C90 days, people wrote code such as this:

typedef struct
{
  header stuff;
  ...
  int data[1]; // the "struct hack"
} protocol;

其中,data会被使用,就好像它具有超出数组的可变大小一样,具体取决于标头部分中的内容.这样的代码是错误的,通常将数据写入填充字节,并通常调用数组超出范围的未定义行为.

where data would then be used as if it had variable size beyond the array depending on what's in the header part. Such code was buggy, wrote data to padding bytes and invoked array out-of-bounds undefined behavior in general.

gcc通过添加空/零数组作为编译器扩展来解决此问题,尽管该代码不再具有可移植性,但该代码的行为没有错误.

gcc fixed this problem by adding empty/zero arrays as a compiler extension, making the code behave without bugs, although it was no longer portable.

C标准委员会认识到此gcc功能很有用,因此他们在1999年向C语言添加了 flexible array成员.此后,由于使用了gcc功能,因此gcc功能被认为已过时. C标准的灵活数组成员是首选.

The C standard committee recognized that this gcc feature was useful, so they added flexible array members to the C language in 1999. Since then, the gcc feature is to be regarded as obsolete, as using the C standard flexible array member is to prefer.

由链接的gcc文档识别:

As recognized by the linked gcc documentation:

不建议在其他情况下声明零长度数组,包括作为结构对象的内部成员或作为非成员对象.

Declaring zero-length arrays in other contexts, including as interior members of structure objects or as non-member objects, is discouraged.

这就是您的代码所要做的.

And this is what your code does.

请注意,未传递任何编译器选项的gcc默认为-std=gnu90(gcc< 5.0)或-std=gnu11(gcc> 5.0).这样可以为您启用所有非标准扩展,因此程序可以编译但不链接.

Note that gcc with no compiler options passed defaults to -std=gnu90 (gcc < 5.0) or -std=gnu11(gcc > 5.0). This gives you all the non-standard extensions enabled, so the program compiles but does not link.

如果您要符合标准的行为,则必须编译为

If you want standard compliant behavior, you must compile as

gcc -std=c11 -pedantic-errors

-pedantic标志禁用gcc扩展,并且链接器错误将按预期切换为编译器错误.对于像您这样的空数组,您将得到:

The -pedantic flag disables gcc extensions, and the linker error switches to a compiler error as expected. For an empty array as in your case, you get:

错误:'arr'中缺少数组大小

error: array size missing in 'arr'

对于零长度数组,您将得到:

And for a zero-length array you get:

错误:ISO C禁止大小为零的数组"arr" [-Wpedantic]

error: ISO C forbids zero-size array 'arr' [-Wpedantic]


int arr[]起作用的原因是因为这是 临时定义的数组声明em> 与外部链接(请参阅C17 6.9.2).它是有效的C,可以视为前向声明.这意味着在代码的其他地方,编译器(或更确切地说是链接器)应该期望找到例如int arr[10],该引用随后引用相同的变量.这样,在知道大小之前,可以在代码中使用arr. (我不建议您使用此语言功能,因为它是意大利面条式编程"的一种形式.)


The reason why int arr[] works, is because this is an array declaration of tentative definition with external linkage (see C17 6.9.2). It is valid C and can be regarded as a forward declaration. It means that elsewhere in the code, the compiler (or rather the linker) should expect to find for example int arr[10], which is then referring to the same variable. This way, arr can be used in the code before the size is known. (I wouldn't recommend using this language feature, as it is a form of "spaghetti programming".)

使用static时,可以通过强制变量具有内部链接来阻止在其他位置指定数组大小的可能性.

When you use static you block the possibility to have the array size specified elsewhere, by forcing the variable to have internal linkage instead.

这篇关于为什么该语句在gcc中产生链接器错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆