打字警告

时间:2012-03-21 16:13:13

标签: linux gcc strict-aliasing type-punning

我想做这样的事情:

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

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

return EQ4(s1,s2);

但是gcc正在产生这个警告:警告:解除引用类型惩罚指针会破坏严格别名规则。

由于我没有将解除引用的指针指定给指针变量,因此我认为我所做的事情并不是为了严格别名的目的而取消引用。

我试过了:

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

没有任何区别。

redhat linux版本2.6.32-220,gcc版本= 4.4.6

有没有办法使用严格别名警告,但仍然可以这样做?

谢谢!

修改

这些不起作用:

#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_))

这有效:

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

你们都怎么看待这个?

2 个答案:

答案 0 :(得分:2)

警告是因为不保证字符串的对齐方式与声明整数变量时的方式相同。因此,当CPU需要获取整数值时,您可能会降低它的效率(因此警告)。

你可以从整数开始:

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);

注意:
1)您必须确保复制字符串的终止'\0'字符,因为这将触及a之外的内存(或b })如果您提供了示例(请参阅下一个注释) 2)您必须确保您的字符串不大于您正在使用的特定平台上的int大小,否则您(再次)触摸不属于int的内存。

答案 1 :(得分:1)

在您的代码中,如果您在此情况下进行分配,则无关紧要。您的宏无论如何都会生成加载/存储指令,这些指令需要由编译器进行排序。

处理严格别名问题的一种方法是使用联合。

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;
}

另一种方法是使用restrict关键字。使用此方法,您可以保证不会出现别名,编译器可以自由地按照其认为合适的方式对操作进行排序,而不会产生获得不需要的结果的风险。但是,请记住,这是一种合约编程。如果你错了,或者有人改变了程序,这可能会导致很难找到错误。