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?
The “invalid use of void expression” error occurs in C/C++ when we try to assign a call to a void function to a variable. It also occurs when a void function is cast to another data type.
The C standard specifies that zero-length formats are allowed. -Wformat-nonliteral. If -Wformat is specified, also warn if the format string is not a string literal and so cannot be checked, unless the format function takes its format arguments as a va_list .
It appears that at least the C11 standard disallows this:
6.3.2.1/1 An lvalue is an expression (with an object type other than void) that potentially designates an object.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With