2011-12-31 2 views
1

Я определил пользовательский макрос assert. Это отлично подходит для всех других сравнений. Тем не менее, я получаю ошибку компиляции:C++: ошибка компилятора при сравнении указателей с использованием макросов

ISO C++ forbids comparison between pointer and integer 

при использовании макроса, показанное ниже (DWASSERT) сравнивать указатели, как в коде ниже.

#define DWASSERT(condition,printstatement) if(!condition){ printf(printstatement); assert(condition); } 

#include <stdio.h> 

int main() 
{ 
    int target = 0; 
    int* ptr1 = &target; 
    int* ptr2 = &target; 

    //Normal comparison works fine 
    if(ptr1 == ptr2) 
     printf("Equal"); 

    //Comparison using Macro generates compiler 
    //error on the next line 
    DWASSERT(ptr1 == ptr2, "Pointers not equal!\n"); 
    return 0; 
} 

В то время как я могу просто избегать использования DWASSERT для этого случая, мне любопытно, почему генерируется эта ошибка компилятора.

+0

попробуйте помещать выражение сравнения в круглые скобки, например: 'DWASSERT ((ptr1 == ptr2)," Указатели не равны! \ N ");' – Yaniro

+0

При написании макроса, когда используется один из макропараметров, он должен быть обернут в parens по умолчанию. Только когда-либо удаляйте parens, если вы знаете, что их нужно удалить (и почему). Существует несколько применений макросов, в которых добавление парнеров вызывает проблемы, но подавляющее большинство падает другим путем. –

+2

Вы также должны перенести этот макрос, чтобы он неожиданно не взаимодействовал с операторами 'if' /' else': http://stackoverflow.com/questions/923822/whats-the-use-of-do-while0 -when-we-define-a-macro –

ответ

8

Проблема заключается в том, что DWASSERT(ptr1 == ptr2, ... получает расширена
if(!ptr1 == ptr2){ printf(...

Вы видите, что происходит? !ptr1 == ptr2 эквивалентен (!ptr1) == (ptr2), а так как !ptr1 - целочисленный тип, а ptr2 - тип указателя, вы получаете свою ошибку.

Что вам нужно сделать, чтобы исправить это изменить определение макроса:

#define DWASSERT(condition,printstatement) if(!(condition)){ printf... 

Кроме того, имейте в виду, что это плохая идея использовать printf так, как вы есть, с произвольная строка как формат. В какой-то момент кто-то даст вам строку с %, и все сломается. Вы должны использовать что-то вроде puts(x) или printf("%s", x).

+0

Отметил пункт относительно printf. Благодаря! – balajeerc

3

Изменить

if(!condition) 

Для

if(! (condition)) 

То, как вы сделали это, ! применяется к первому указателю в сравнении, а не результат сравнения, имеет более высокий приоритет, чем ==.

В круглых скобках следует всегда включать макропараметры, чтобы избежать подобных проблем. Иногда компилятор не предупреждает вас, и вы будете тянуть свои слухи на ночь, ища ошибку.

0

Попробуйте

DWASSERT((ptr==ptr2), "Pointers not equal!\n"); 
+0

Это фиксирует симптом, но не вылечивает болезнь. – Gabe

+0

Я думаю, это зависит от того, кто его использует. Я принудительно скопирую условия для таких вещей. –

1

Put скобку вокруг условия в if в макросе:

#define DWASSERT(condition,printstatement) if(!(condition)){ printf(printstatement); assert(condition); } 

Компилятор видит:

if (!ptr1 == ptr2) { ... } 

который интерпретируется как:

if ((!ptr1) == ptr2) { ... } 

Это не то, что вы хотите. Но вы действительно должны использовать для этого подходящую функцию - условие потенциально оценивается дважды с вашим макросом. Могут быть обстоятельства, при которых второй тест мог бы дать разные результаты от первого, что принесло бы очень неожиданные результаты.

int i = -1; 

DWASSERT(++i, "will I assert?"); 

(Если вы действительно должны использовать макрос, вы должны создать анонимный блок в нем, и сохранить оценку состояния во временном bool. Это часто делается с do { ... } while(0) конструкцией.)

+0

Утверждение - одно из немногих мест, где я использую макросы вместо функций (проще в трассировке), но я бы удостоверился, что условие оценивалось только один раз по причинам, о которых вы упомянули. –

Смежные вопросы