Question

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?

Was it helpful?

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.

OTHER TIPS

It does not matter if you, in your code, make assignments in this case. Your macro will generate load/store instructions anyways and these need to be ordered by the compiler.

One way to deal with strict aliasing issues is to use unions.

inline bool my_equal(char *a, char *b) {
  union {
    char *cPointer;
    int *iPointer;
  } left_union = { .cPointer = a }, right_union = { .cPointer = b };

  return *left_union.iPointer == *right_union.iPointer;
}

Another is to use the restrict keyword. Using this, you guarantee that there is no aliasing going on and the compiler is free to order the manipulations any way it sees fit without running the risk of getting unwanted results. But, keep in mind that this is a kind of contract programming. If you're wrong, or someone changes the program, this might result in hard to find bugs.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top