2012-03-21 6 views
0

Я хочу сделать что-то вроде этого:типа каламбурил предупреждение

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

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

return EQ4(s1,s2); 

но НКУ производит это предупреждение: Внимание: разыменования типа каламбурил указатель будет нарушать правила строгого сглаживания.

Я не думал, что то, что я делал, считалось разыменованием для целей строгого сглаживания, поскольку я не назначал разыменованный указатель на переменную указателя.

Я пробовал:

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

, который не имеет никакого значения.

RedHat Linux версии 2.6.32-220, GCC версии 4.4.6 =

Есть ли способ использовать строгое предупреждение сглаживанием, но все-таки делать такие вещи, как это?

Спасибо!

EDIT

Они не работают:

#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

+0

Спасибо за все ответы всем. Предупреждение из-за выравнивания интересно. Мы компилируем с -march = 686. В более ранней версии gcc я сравнивал свои трюки memcmp, и они появились намного быстрее, несмотря на не оптимальное выравнивание. Текущая версия gcc кажется улучшенной - она ​​и снижает memcmp для небольших диапазонов. Я, вероятно, смогу прекратить использовать многие из этих трюков, но не все, поэтому меня все еще интересуют все разные идеи. – johnnycrash

ответ

2

Предупреждение связано с тем, что строка не может быть выровнена так же, как при объявлении целочисленной переменной. Таким образом, когда ЦП необходимо получить целые значения, вы потенциально делаете его менее эффективным, чем это могло бы быть (следовательно, предупреждение).

Вы могли бы начать с целыми числами, чтобы начать с:

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

«Другой должен использовать ключевое слово ограничения.», Пожалуйста, объясните – curiousguy