2013-04-04 2 views
1

Я использую приведенный ниже код для утверждения в «выпуске», в течение некоторого времени не испытывая никаких проблем. Затем появился Visual Studio 2010 Pro SP1, и все пошло на юг, as also happened to mr. Krunthar.Ассемблеры и неиспользуемые переменные в Visual Studio 2010 SP1

Проблема заключается в том, когда у меня есть кусок кода, в котором я делаю вменяемости проверки, как это:

#define ASSERT(condition, msg) do { (void)sizeof(condition); } while (0,0) 
    // Note: (0,0) is to avoid warning C4127: conditional expression is constant 

{ 
    int result = CallMeOnce(); // its side effects are the important stuff 
    // perform additional sanity checks in debug 
    ASSERT(result >= 0, "too low"); 
    ASSERT(result <= 100, "too high"); 
    ASSERT(!isPrime(result), "too prime"); 
} 

VS2010 выплевывает warning C4189: 'result' : local variable is initialized but not referenced

Я в недоумении о том, как исправить это:

  • код как (void)(condition) будет выполнять любое выражение передается как условие, которое является не не
  • Ввод CallMeOnce() внутри выражения ASSERT невозможно
  • Рефакторинг все различные CallMeOnce() S не вариант
  • Я предпочел бы не писать код люльки как (void)result, if (result == result) {} или UNREFERENCED_PARAMETER(result) (или эквивалент) вне макроса, только чтобы избежать предупреждение, так как это делает код еще труднее читать (загрязнение), и его легко забыть при написании кода в Debug. Также: во многих местах!

Я рассматриваю возможность создания другого макроса (ASSERTU?) Только для переменных, но он чувствует себя так ... изворотливый!
Кто-нибудь нашел лучший выход?

Большое спасибо!

Edit: осветленный предпочтение переменной обработки на уровне

+0

Включите предупреждение прочь. –

+0

И пропустите все другие действительно неиспользованные переменные, загромождающие код? :) – ptor

ответ

0

Кажется, я где-то попал!

#define ASSERT(condition, msg) \ 
    do { \ 
    if (0,0) { \ 
     (void)(condition); \ 
    } \ 
    } while (0,0) 

Обязательное объяснение:

(void)(condition); подавляет C4189, но будет выполнять любое выражение или вызов функции передается в

Однако if (false) {...} будет убедиться, что все (допустимое выражение)».. .. "может быть, он не будет выполнен. Фаза оптимизации кода увидит это как мертвый код и выбросит его (никакого кода, сгенерированного вообще для блока в моих тестах!).

И, наконец, уловка совы (0,0) предотвратит C4127, что, кажется, совершенно бесполезное предупреждение в первую очередь, но эй, меньше беспорядка на выходе компиляции!

Единственная слабость, которую я могу найти для этого решения, состоит в том, что condition необходимо подбирать, поэтому если вы #ifdef -вычитаете часть выражения, это вызовет ошибку. Возможно, он также компилирует (хотя и не вызывает) код для вызываемых функций; больше исследований было бы полезно.

0

вызывающего абонента в вашей Assert макро у вас есть

(void)sizeof(condition); 

предположительно этот код был написан кем-то еще, так что объяснение:

в Роль броузера (void) заключается в том, чтобы сообщить компилятору, что вы действительно намеревались сделать это заявление без выражения ничего не делать.

сейчас делают то же самое для вашего result

, что было легко, не так ли? иногда решение просто смотрит вам в лицо.;-)


, кстати, когда эта конструкция используется для подавления предупреждений о неиспользуемых формальных аргументов, вы можете захотеть добавить переопределение названия, как

(void) unusedArg; struct unusedArg; 

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

однако, ошибка генерируется Visual C++ не совсем информативен


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

+0

Спасибо за предложение, но я предпочел бы иметь более сложный макрос, чем результат использования (void); в других местах – ptor

+0

@ptor: компилятор реагирует на неиспользуемую переменную 'result' на каждом * сайте * вызова. вы ничего не можете сделать по этому поводу в своем макросе утверждения без изменения сайтов вызова. что я сказал, что макрос 'ASSERT', как представлено, ничего не делает? так как это не ваш реальный код (или, альтернативно, ваш код должен быть исправлен), возможно, представленный примерный сайт вызова не является репрезентативным для реального сайта вызова? в этом случае, возможно, вы можете изменить использование макроса 'WITH' (a la C#' using') или аналогичного. –

+0

@ cheers-and-hth-alf: это ОЧЕНЬ представитель реального сайта звонка, причем фактические имена функций восстанавливаются по понятным причинам. Почему вы думаете иначе? assert не делает ничего, потому что, поскольку это для сборки Release, НЕ ДОЛЖЕН ничего делать. Или я пропущу что-то очевидное? – ptor

0

Вы можете использовать UNREFERENCED_PARAMETER макрос.

+0

Зачем использовать недокументированную визуальную C++-специфическую вещь, когда стандартный C++ имеет переносимую конструкцию, которая выполняет эту работу, более чистым менее подробным способом. –

+1

@ Cheersandhth.-Alf 1. Как и в OP: «* Код как (void) (условие) будет выполнять любое выражение, переданное как условие, которое не равно no * ". 2. 'UNREFERENCED_PARAMETER' читается, и ничто не мешает определить его для любого компилятора - это тривиально. – SomeWittyUsername

+0

icepack: извините, это мусор, аба balddash –

0

Это намного приятнее. Кроме того: выражение вместо констатация

#define ASSERT(condition, msg) (false ? (void)(condition) : (void)0) 

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

0

Вы можете использовать пары __pragma(warning(push)) __pragma(warning(disable: 4127)) и __pragma(warning(pop)) для тишины C4127 только для линии ASSERT.

Затем (void)(true ? (void)0 : ((void)(expression))) молчание C4189.

Это выписка из my own implementation of an assertion macro.

Макрос PPK_ASSERT(expression) в конечном счете будет расширяться до PPK_ASSERT_3(level, expression) или PPK_ASSERT_UNUSED(expression) в зависимости от того, включены или запрещены утверждения.

#define PPK_ASSERT_3(level, expression, ...)\ 
    __pragma(warning(push))\ 
    __pragma(warning(disable: 4127))\ 
    do\ 
    {\ 
    static bool _ignore = false;\ 
    if (PPK_ASSERT_LIKELY(expression) || _ignore || pempek::assert::implementation::ignoreAllAsserts());\ 
    else\ 
    {\ 
     if (pempek::assert::implementation::handleAssert(PPK_ASSERT_FILE, PPK_ASSERT_LINE, PPK_ASSERT_FUNCTION, #expression, level, _ignore, __VA_ARGS__) == pempek::assert::implementation::AssertAction::Break)\ 
     PPK_ASSERT_DEBUG_BREAK();\ 
    }\ 
    }\ 
    while (false)\ 
    __pragma(warning(pop)) 

и

#define PPK_ASSERT_UNUSED(expression) (void)(true ? (void)0 : ((void)(expression))) 
Смежные вопросы