Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why has GCC started warning on taking the address of a void expression?

Tags:

c

gcc

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?

like image 653
Dolda2000 Avatar asked Dec 03 '14 03:12

Dolda2000


People also ask

What is invalid use of void expression?

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.

What is Wformat in C?

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 .


1 Answers

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.

like image 125
2 revs, 2 users 92% Avatar answered Sep 23 '22 19:09

2 revs, 2 users 92%