Переменная оптимизирована компилятором - PullRequest
1 голос
/ 03 июня 2009

Я начал отлаживать код, пытаясь найти свою ошибку. Когда я пытаюсь p tlEntries из отладчика, я получаю

<variable optimized away by compiler>

Сообщение

при остановке на операторе if. Вот мой код:

NSArray *tlEntries = [[NSArray alloc] initWithArray:[self fetchJSONValueForURL:url]];
for (NSDictionary *info in tlEntries) 
{
    if ([info objectForKey:@"screen_name"] != nil)
         NSLog(@"Found %@ in the timeline", [info objectForKey:@"screen_name"]);
}

Ранняя отладка дает мне уверенность, что URL действительно возвращает действительный NSArray, но я не понимаю, почему tlEntries "оптимизируется".

Ответы [ 4 ]

17 голосов
/ 03 июня 2009

Правильное решение состоит в том, чтобы объявить переменную следующим образом:

volatile NSArray *tlEntries;

Действительно, ключевое слово volatile используется именно для того, чтобы сообщить компилятору, что он не должен каким-либо образом пытаться оптимизировать код, связанный с этой переменной. С уважением.

6 голосов
/ 03 июня 2009

Компилятор, вероятно, заметил, что вы используете tlEntries только дважды в начале, и не используете его вообще в цикле. Циклы создают объект перечисления вместо сохранения ссылки на объект контейнера, если я правильно помню. Таким образом, tlEntries должен быть действительным для первой строки, а затем для остальных.

Идея: Вы можете заставить компилятор сохранить его, используя tlEntries где-то позже в функции. Что-то вроде

NSPrint(@"IGNORE THIS LINE %p", tlEntries);

Лучшая идея: Вы можете установить оптимизацию на -O0. Это настоятельно рекомендуется для отладки кода. Он должен быть установлен в -O0 автоматически, если вы используете «Debug» вместо «Release», но вы можете это изменить.

3 голосов
/ 04 июня 2009

Когда оптимизация компилятора включена, переменные часто «оптимизируются», помещая их в регистры или другие приемы, такие как переупорядочение операторов. Если вы используете какой-либо флаг -O, отличный от -O0, это может произойти.

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

В качестве временного обходного пути вы можете объявить переменную «volatile». Как правило, это не является хорошим долгосрочным решением, поскольку оно не позволяет компилятору выполнять какие-либо оптимизации с использованием этой переменной.

Другой обходной путь - использовать старомодное ведение журнала. Что-то вроде:

NSLog(@"Entries initialized as: %@", tlEntries);

Наконец, вы также можете скомпилировать с -O0. Многие люди рекомендуют это для профиля проекта Debug . Хотя это предотвращает оптимизацию, оно значительно облегчает отладку. Пошаговые инструкции на самом деле предсказуемы, и переменные могут быть просмотрены. К сожалению, он имеет довольно неприятный побочный эффект с версией gcc, которую поставляет Apple: когда действует -O0, вы не можете получать предупреждения об использовании переменных до инициализации. (Лично я нахожу это предупреждение достаточно полезным, так что я готов испытать боль от отладки, будучи менее удобным.)

P.S. В опубликованном фрагменте есть утечка памяти; для ясности следует добавить дополнительную строку:

[tlEntries release];
1 голос
/ 03 июня 2009

Предполагая, что вы никогда не будете использовать эту переменную позже (что кажется разумным, если компилятор оптимизировал ее), один очень важный способ, который вы могли бы использовать для решения проблемы (аналогично примеру Дитриха, хотя лучше для вашей программы), заключается в а:

[tlEntries release];

В противном случае вы точно потеряете эту память. Это заставит компилятор увидеть объект, используемый позже (как и NSPrint), поэтому он не будет оптимизирован.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...