问题描述
几个GCC版本之前,我可以做这样的整洁的事情:
$ objcopy -I binary -O elf64-x86-64 -B i386 foo.png foo.png.o
...在C中加入以下内容,以SDL图像加载为例:
extern void _binary_foo_png_start;
extern void _binary_foo_png_start;
SDL_Surface * image = IMG_Load_RW(SDL_RWFromMem(& _binary_foo_png_start,& _binary_foo_png_end));
然后我会链接 foo.png.o
连同来自C文件的目标文件,并得到一个整齐包含 foo.png
的可执行文件。
这些天,我仍然可以做到这一点,但GCC警告我:
foo.c:57:19:warning:taking类型'void'的表达式地址
foo.c:57:44:warning:获取类型'void'的表达式地址
显然它仍然有效,并且据我所知,它确实按照它应该做的。符号本身没有明确定义的类型,因此将它们声明为 void
似乎是合适的。我的意思是,我可以 给他们任何其他任意类型,它仍然会工作,看到我只是想要他们的地址,但声明他们
那么为什么GCC突然决定开始警告我这件事?是否还有其他一些首选的方式应该完成这项工作?
看来至少C11标准不允许这样做: p>
如果您的表达式不是左值,则不能取其地址。
声明的有效性
extern void _binary_foo_png_start;
有问题,因为它可以说没有声明一个对象(一个对象不能有空隙
)。我试过的四个C编译器中有两个接受它。其中一个编译器接受& _binary_foo_png_start
。一个错误提交了。
从历史的角度来看,似乎曾经有人允许这样的结构(这也许可以解释为什么海湾合作委员会接受它)有些类似讨论可以在中找到。请记住,诸如左值的相关定义在C90,C99和C11中有所不同。
A couple of GCC versions ago, I could do neat things like this:
$ objcopy -I binary -O elf64-x86-64 -B i386 foo.png foo.png.o
... coupled by the following in C, as an example with SDL image loading:
extern void _binary_foo_png_start;
extern void _binary_foo_png_start;
SDL_Surface *image = IMG_Load_RW(SDL_RWFromMem(&_binary_foo_png_start, &_binary_foo_png_end));
Then I would link foo.png.o
together with the object file from the C file and get an executable which neatly contained foo.png
.
These days, I can still do that, but GCC warns me about it:
foo.c:57:19: warning: taking address of expression of type ‘void’
foo.c:57:44: warning: taking address of expression of type ‘void’
Clearly it still works, and as far as I can tell, it really does what it's supposed to. The symbols themselves have no well defined type, and therefore it seems fitting to declare them as void
. I mean, sure, I could just as well give them any other arbitrary type and it would still work just as well seeing as how I just want their address anyway, but declaring them void
seemed nicer than just making up some type.
So why has GCC suddenly decided to start warning me about this? Is there some other preferred way that this should be done?
It appears that at least the C11 standard disallows this:
If your expression is not an lvalue, you cannot take its address.
Validity of the declaration
extern void _binary_foo_png_start;
is questionable, because it arguably does not declare an object (an object cannot have type void
). Two out of four C compilers I have tried accept it though. One of these compilers accepts &_binary_foo_png_start
. A bug is filed.
On a historic note, it seems that it once was the intent to allow such constructs (which may explain why Gcc used to accept it) some similar discussion can be found in DR 12. Keep in mind that relevant definitions such as lvalue differ in C90, C99 and C11.
这篇关于为什么海湾合作委员会在采取无效表达的地址时开始警告?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!