2012-03-21 38 views
0

我想要做這樣的事情:型punned警告

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

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

return EQ4(s1,s2); 

但GCC是生產這樣的警告:警告:提領型punned指針將打破嚴格走樣規則。

我不認爲我在做什麼計算作爲解除引用的嚴格別名的目的,因爲我沒有將解引用的指針分配給指針變量。

我想:

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

這沒有什麼區別。

紅帽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) 

你都覺得這是什麼?

+1

正確排列它們,不知道gcc但icc能識別正確對齊的'char *'s並且不會發出警告 – hroptatyr 2012-03-21 16:25:57

+0

感謝所有人的回覆。由於對齊的警告很有趣。我們正在編譯-march = 686。在gcc的早期版本中,我對我的memcmp技巧進行了基準測試,儘管沒有最佳對齊方式,但它們出現得更快。當前版本的gcc似乎有所改進 - 它爲小範圍降低了memcmp。我可能會停止使用許多這些技巧,但不是全部,所以我仍然對所有不同的想法感興趣。 – johnnycrash 2012-03-21 17:33:56

回答

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

如果你在你的代碼中在這種情況下做出了任務,那並不重要。無論如何,您的宏將生成加載/存儲指令,這些需要由編譯器進行排序。

處理嚴格別名問題的一種方法是使用聯合。

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關鍵字。通過這種方式,您可以保證不會出現鋸齒,編譯器可以自由地按照自己認爲合適的方式對操作進行排序,而不會產生不必要的結果。但請記住,這是一種合約編程。如果你錯了,或者有人改變了程序,這可能會導致很難找到錯誤。

+0

「_另一種是使用restrict keyword._」請解釋 – curiousguy 2012-07-20 18:19:26