Как избежать предупреждений «неиспользуемой переменной» компилятором с условно скомпилированными заменами NSLog? - PullRequest
2 голосов
/ 13 сентября 2010

Это вытекает из моего поиска умного варианта NSLog(). Одной из ключевых особенностей BetterLog() является то, что замена NSLog() ничего не компилирует для сборок релизов и дистрибутивов. Предлагаемое решение (см., Например, Правда ли, что не следует использовать NSLog () в производственном коде? ) - это определение символа препроцессора для управления определением BetterLog() в зависимости от типа сборки. Как правило:

#ifdef DEBUG_MODE
    #define DebugLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
    #define DebugLog( s, ... ) 
#endif

где DEBUG_MODE будет определяться как символ препроцессора только для отладочных сборок.

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

if (error) {
    NSString *titleString = @"Error downloading thumbnail, will rebuild it";
    NSString *messageString = [error localizedDescription];
    NSString *moreString = [error localizedFailureReason] ? [error localizedFailureReason] : NSLocalizedString(@"Check the URL.", nil);
    BetterLog(@"%@: %@. %@", titleString, messageString, moreString);
} // silently ignoring *this* error is OK.

Здесь все три строки выдают предупреждения компилятора. И я ненавижу предупреждения компилятора.

Конечно, этого невозможно избежать, не включив условно что-либо в сами объявления переменных. Я сделал следующую попытку, но она не сработала:

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

Затем я попытался воспользоваться оптимизацией удаления мертвого кода компилятора:

if (DEBUG_MODE && error) {
    // snip
}

Код в порядке: он корректно удаляется в режиме разблокировки. Тем не менее, компилятор по-прежнему выдает предупреждения о неиспользованных переменных.

Итак, вопрос: разве нельзя сделать что-то лучше, чем уродливый:

#if DEBUG_MODE
if (error) {
    // snip
}
#endif

1 Ответ

1 голос
/ 13 сентября 2010

Один из вариантов будет:

#define BetterLog(...) do { (void)(__VA_ARGS__); } while (0)

Это имеет то преимущество, что если вы достигнете BetterLog (), любые побочные эффекты его аргументов будут оценены, и это будет чистое утверждение, поэтому не будет ошибкой писать if (x) BetterLog(@"%@", x); (что приведет к нарушению следующего оператора с использованием вашего макро).

Лично я предпочитаю использовать «уродливый» подход препроцессора, потому что он явно касается исключения кода отладки.

...