Search code examples
linuxgccstrict-aliasingtype-punning

type-punned warning


I want to do something like this:

#define EQ4(a_,b_) (*(int*)(a_)==*(int*)(b_))

char *s1 = "food";
char *s2 = "fred";

return EQ4(s1,s2);

but gcc is producing this warning: Warning: dereferencing type-punned pointer will break strict-aliasing rules.

I didn't think what I was doing counted as dereferencing for the purposes of strict aliasing, since I was not assigning the dereferenced pointer to a pointer variable.

I tried:

#define EQ4(a_,b_) (*(const int const *)(a_)==*(const int const*)(b_))

which made no difference.

redhat linux version 2.6.32-220, gcc version = 4.4.6

Is there any way to use the strict aliasing warning, but still do things like this?

Thanks!

EDIT

These don't work:

#define EQ4(a_,b_) (*(int*)(char*)(a_)==*(int*)(char*)(b_))
#define EQ4(a_,b_) (*(int*)(void*)(a_)==*(int*)(void*)(b_))
#define EQ4(a_,b_) (*(int* __attribute__((__may_alias__)))(a_)== \
                    *(int* __attribute__((__may_alias__)))(b_))

This works:

typedef union bork { char a[4], int n32 } __attribute__((__may_alias__)) TBork;
#define EQ4(a_,b_) ((TBork*)(a_)->n32==(TBork*)(b_)->n32)

What do you all think of this?


Solution

  • The warning is because the string is not guaranteed to be aligned the same way as when an integer variable is declared. Thus when the CPU needs to fetch the integer values, you are potentially making it less efficient than it could be (hence the warning).

    You could start with integers to begin with:

    int a;
    int b;
    char* as=(char*)(&a);
    char* bs=(char*)(&b);
    as[0]='f'; as[1]='o'; ...
    bs[0]='f'; bs[1]='r'; ...
    return EQ4(a, b);
    

    Notes:
    1) you will have to make sure you do not copy the terminating '\0' character of the string, because that will be touching memory outside of a (or b) in case of the examples you provided (see next Note).
    2) you will have to make sure your strings are no larger than the size of int on the particular platform you are using, otherwise you are (again) touching memory that does not belong to the int.