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?

+3


source to share


1 answer


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.

+3


source







All Articles