Why is this assignment of a pointer variable allowed?
While debugging my program, I came across strange behavior of the gcc compiler. I don't know what is the correct name to describe this, but take a look at the code below.
Basically, I had a function that got it void* arg
as an argument. Then he cast it into a different type of pointer HTTPRequest*
. However, I selected the wrong variable, so the code looked like
void someCallback(void* arg) {
HTTPRequest* req = (HTTPRequest*) req;
FreeRequest(req);
//re-setup request, other stuff..
}
The program was then broken into FreeRequest
with a help SIGSEGV
when it tried to cancel the pointer. Upon further examination, a req
always matters NULL
.
It took me a while to realize that the actors I did were only done in the wrong way - it had to be
HTTPRequest* req = (HTTPRequest*) arg;
Then everything worked. However, I was puzzled that gcc
I allowed me not only to compile this code, but also not to warn about it on this line.
Consider a minimal example
#include <stdlib.h>
#include <stdio.h>
void someFunc(void* arg) {
int* a = (int*) a;
printf("a = %p\n", a);
printf("*a = %d\n", *a);
}
int main() {
int b = 42;
someFunc(&b);
return 0;
}
Compiled with
gcc -Wall -Wextra -Wpedantic -o test -O0 test.c && test.exe
Compiler outputs
test.c: In function 'someFunc':
test.c:7:9: warning: format '%p' expects argument of type 'void *', but argument 2 has type 'int *' [-Wformat=]
printf("a = %p\n", a);
^
test.c:4:21: warning: unused parameter 'arg' [-Wunused-parameter]
void someFunc(void* arg) {
^
And the program outputs:
a = 0061FFCC *a = 6422500
When optimized with atleast, O1
it outputs:
gcc -Wall -Wextra -pedantic -o test -O1 test.c && test.exe
test.c: In function 'someFunc':
test.c:7:9: warning: format '%p' expects argument of type 'void *', but argument 2 has type 'int *' [-Wformat=]
printf("a = %p\n", a);
^
test.c:4:21: warning: unused parameter 'arg' [-Wunused-parameter]
void someFunc(void* arg) {
^
And exits
a = 00000000
Then it freezes.
So the question is, why does gcc allow compilation of expressions of the above form? This is obviously undefined behavior. Then why are there no warnings about this, even if all warnings are on?
source to share
Why does gcc allow compilation of expressions of the above form? This is obviously undefined behavior.
Because the standard allows it. undefined behavior allows the compiler to optimize writing code in C. You can read this excellent article from the llvm developer .
Then why are there no warnings about this, even if all warnings are on?
-Wall -Wextra
do not activate all warnings in gcc. clang does -Weverything
, but gcc does not.
The compiler cannot print a warning message for everything. The warning that the compiler has to print if it wants to be standard is warned.
What you are doing is undefined behavior and it is not required in the standard to print a warning.
clang 4.0.0 has a warning for this -Wuninitialized
:
warning: variable 'a' is uninitialized when used within its own initialization [-Wuninitialized] int* a = (int*) a;
gcc 7.1.1 has a warning for this -Winit-self
:
warning: ‘a’ is used uninitialized in this function [-Wuninitialized] int* a = (int*) a;
Note. Your listing is useless, C will support any void *
valid pointer type.
source to share