Что означает "note: containing loop" ?

Для новичков как вообще в Linux, так и в конкретной теме, к которой относится вопрос.

Модератор: Bizdelnick

Ответить
MiK13
Сообщения: 1180
ОС: Linux Debian

Что означает "note: containing loop" ?

Сообщение MiK13 »

Когда-то я потерял несколько часов, не понимая почему у меня не работает программа. Т.е. не выполняется вызов функции. А причина оказалась в том, что я, набирая текст, случайно задел клавишу \, расположенную рядом с клавишей "Ввод". В результате следующая строка явилась продолжением комментария. После этого я стал транслировать все программы с опцией -Wall и добиваться, чтобы компилятор не выдавал ни одного предупреждения.
И вот при трансляции программы в 8-м Debianе, Jessie вдруг на цикл

Код: Выделить всё

for(int i=0;i<6;i++)
появляется сообщение
note: containing loop. Причём, при трансляции в Wheezy никакого предупреждения (точнее, замечания) не появлялось.
Сначала я подумал, что, может быть потому, что в этой функции уже объявлена переменная i. Заменил её на iii, но ничего не изменилось. Замечание пропало когда я из строки компиляции убрал опцию -O2 (точнее, заменил её на -O0). А оптимизация (по скорости) для этой программы очень желательна.

Почему может возникать такое замечание и можно ли от него избавиться, сохраняя оптимизацию?
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Что означает "note: containing loop" ?

Сообщение Bizdelnick »

MiK13 писал(а):
04.11.2015 23:14
следующая строка явилась продолжением комментария

Подсветка синтаксиса очень хорошо помогает от таких ошибок. Хотя -Wall всё равно полезная штука.

MiK13 писал(а):
04.11.2015 23:14
Почему может возникать такое замечание и можно ли от него избавиться, сохраняя оптимизацию?

Лень гуглить, поэтому пальцем в небо: оптимизатор разворачивает цикл, вот и выводит такое сообщение. А зачем от него избавляться? Мешает, что ли?

Upd. Посмотрите man gcc на предмет опции -fopt-info-options, вроде бы оно.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
MiK13
Сообщения: 1180
ОС: Linux Debian

Re: Что означает "note: containing loop" ?

Сообщение MiK13 »

Bizdelnick писал(а):
04.11.2015 23:52
MiK13 писал(а):
04.11.2015 23:14
следующая строка явилась продолжением комментария

Подсветка синтаксиса очень хорошо помогает от таких ошибок.

Вся проблема была в том, что я тогда работал в основном под виндой, а транслировал на виртуальной машине. И в качестве редактора использовал mcedit. А он, хотя и подсвечивает синтаксис, но такие вещи не обнаруживает (до сих пор). А vim для меня слишком непривычный. Хотя в нём проверил -- подсвечивает. Сейчас использую geany, в нём я бы сразу это обнаружил.

Bizdelnick писал(а):
04.11.2015 23:52
MiK13 писал(а):
04.11.2015 23:14
Почему может возникать такое замечание и можно ли от него избавиться, сохраняя оптимизацию?

Лень гуглить, поэтому пальцем в небо: оптимизатор разворачивает цикл, вот и выводит такое сообщение. А зачем от него избавляться? Мешает, что ли?
Да просто хочется, чтобы всё проходило "гладко".
А про это сообщение я спрашивал и у Яндекса и у Google. Но ссылки были на что-то сложное и на английском языке.
Добавка "Что значит" вывела на один интересный пример:

Код: Выделить всё

#include <iostream>
int main() {
    for (int i = 0; i < 4; ++i) {
        std::cout << i*1000000000 << std::endl;
    }
}
при оптимизации -O2 и выше выдаёт аналогичное замечание вместе с предупреждением
warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
При -O1 этого нет. И программа работает нормально.
Но при -O2 цикл почему-то становится бесконечным. Что заставляет внимательнее относиться к предупреждениям.
Причём программа зацикливается при выводе через cout. При выводе через printf зацикливания нет.

Bizdelnick писал(а):
04.11.2015 23:52
Upd. Посмотрите man gcc на предмет опции -fopt-info-options, вроде бы оно.
Спасибо, попробую разобраться.
Спасибо сказали:
Аватара пользователя
s.xbatob
Сообщения: 1139
ОС: Fedora

Re: Что означает "note: containing loop" ?

Сообщение s.xbatob »

Насколько я понял, это предупреждение означает, что оптимизация может наворотить. Помимо бесконечного цикла возможно меньшее количество итераций. Проявляется. когда количество итераций известно заранее и невелико. (я так понимаю - цикл заменяется линейным кодом)
Спасибо сказали:
Аватара пользователя
Hephaestus
Сообщения: 3729
Статус: Многоуважаемый джинн...
ОС: Slackware64-14.1/14.2
Контактная информация:

Re: Что означает "note: containing loop" ?

Сообщение Hephaestus »

MiK13 писал(а):
04.11.2015 23:14
Когда-то я потерял несколько часов, не понимая почему у меня не работает программа. Т.е. не выполняется вызов функции. А причина оказалась в том, что я, набирая текст, случайно задел клавишу \, расположенную рядом с клавишей "Ввод". В результате следующая строка явилась продолжением комментария. После этого я стал транслировать все программы с опцией -Wall и добиваться, чтобы компилятор не выдавал ни одного предупреждения.
И как? Помогает?
Здесь нужно понимать, что таким манером может "вылететь из обращения" целый блок кода.
Тогда никаких предупреждений не будет. Может, я это специально закомментировал, откуда компилятор знает?
Я к тому, что на предупреждения смотреть, конечно, надо, но это не панацея.
Кстати, пользуясь случаем ещё раз помяну утилиту по имени splint, которая есть аналог юникосовой lint и выполняет ту же задачу что и -Wall, только более строго.

MiK13 писал(а):
05.11.2015 01:29
при оптимизации -O2 и выше выдаёт аналогичное замечание вместе с предупреждением
warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
При -O1 этого нет. И программа работает нормально.
Но при -O2 цикл почему-то становится бесконечным. Что заставляет внимательнее относиться к предупреждениям.
Причём программа зацикливается при выводе через cout. При выводе через printf зацикливания нет.
Да, интересно. Я ощущаю острую нехватку знаний в этом вопросе. А в таких случаях я стараюсь найти книгу по теме.
Стало быть, в данном случае нужна инфа по опциям оптимизации gcc.
Я в своё время искал книгу про отладчик gdb и наткнулся на книгу по gcc, автор - Артур Гриффитс.
Толком я её не читал, при беглом просмотре, отдельной главы по оптимизации не обнаружилось. Хотя инфы там вроде бы много и по ключам в том числе.
Ну, ещё нашлось вот это и вот это.
В общем, надо разбираться.
Пускай скрипят мои конечности.
Я - повелитель бесконечности...
Мой блог
Спасибо сказали:
yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: Что означает "note: containing loop" ?

Сообщение yoshakar »

Hephaestus писал(а):
05.11.2015 09:56
Кстати, пользуясь случаем ещё раз помяну утилиту по имени splint, которая есть аналог юникосовой lint и выполняет ту же задачу что и -Wall, только более строго.
Утилита хорошая, но надо понимать отличие от -Wall. Компилятор с -Wall не даёт ложных срабатываний. Там есть пара-тройка дурацких предупреждений, которые лчно я отключаю - они не дают пользоваться некоторыми полезными фичами языка, но ложных срабатываний нет. То есть игнорировать ворнинги компилятора не стоит (почти) никогда. А (sp)lint выдаёт, вообще говоря, кучу ложных срабатываний, как и любой статический анализатор, то есть игнорировать его ворнинги вполне нормально.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Что означает "note: containing loop" ?

Сообщение Bizdelnick »

MiK13 писал(а):
05.11.2015 01:29
хочется, чтобы всё проходило "гладко".

Всё и проходит гладко. Это не сообщение об ошибке, не предупреждение, а просто информация к сведению.

MiK13 писал(а):
05.11.2015 01:29
Добавка "Что значит" вывела на один интересный пример:

Код: Выделить всё

#include <iostream>
int main() {
    for (int i = 0; i < 4; ++i) {
        std::cout << i*1000000000 << std::endl;
    }
}

при оптимизации -O2 и выше выдаёт аналогичное замечание вместе с предупреждением
warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
При -O1 этого нет. И программа работает нормально.

У Вас тут в любом случае происходит целочисленное переполнение. Просто с -O1 оно случается во время работы программы, а с -O2 уже при разворачивании цикла оптимизатором, отсюда и предупреждение.

Upd. Вот так работает:

Код: Выделить всё

#include <iostream>
#include <stdint.h> // или <cstdint> и компилировать с -std=c++11

int main() {
   for (int i = 0; i < 4; ++i) {
       std::cout << int64_t(i) * 1000000000 << std::endl;
    }
}
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
bormant
Сообщения: 1354

Re: Что означает "note: containing loop" ?

Сообщение bormant »

MiK13 писал(а):
05.11.2015 01:29
Но при -O2 цикл почему-то становится бесконечным.

Оптимизатор пытается упростить его, избавившись от умножения, заменив последовательный вывод i*1e6 на i, а шаг цикла на 1e6:

Код: Выделить всё

    for (int i = 0; i <= 3000000000; i+=1000000000) {
        std::cout << i << std::endl;
    }
А поскольку для "int i" условие "i <= 3000000000" истинно для любых i (а условие выхода из цикла недостижимо), то проверять его нет смысла, можно менять на

Код: Выделить всё

    for (int i = 0; ; i+=1000000000) {
        std::cout << i << std::endl;
    }

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

Код: Выделить всё

note: containing loop


Кстати, вот вам отличная иллюстрация того, как UB (в данном случае знаковое переполнение) может влечь любое поведение -- в данном случае повлиять на корректный на первый взгляд код (UB из вывода результата вычисляемого выражения выползло в условие окончания цикла).
Спасибо сказали:
MiK13
Сообщения: 1180
ОС: Linux Debian

Re: Что означает "note: containing loop" ?

Сообщение MiK13 »

Код: Выделить всё

#include <iostream>
int main() {
    for (int i = 0; i < 4; ++i) {
        std::cout << i*1000000000 << std::endl;
    }
}

Проверял поздно ночью, поэтому не сообразил дать ссылку на страницу, где это обнаружил. Вот она
Но потом почитал комментарии и обнаружил в них следующих два интересных (НМВ) замечания.
  • Сгенерировал ассемблерный листинг с помощью g++ -O2 -S -c foo.cpp. Ни одного умножения, зато присутствует строка addl $1000000000, %r12d. Так что похоже, что таки да, убирает лишнее умножение.
  • Что забавно, если заменить endl на '\n', то баг опять перестает проявляться.
Сейчас на работе попробовал проверить этот пример, но нет ни предупреждений, ни зацикливаний.
Правда, на работе у меня Wheezy с компилятором g++ 4.7

Ну и попутно небольшой вопрос: можно ли в тексте программы задавать уровень разный оптимизации для её разных частей?
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Что означает "note: containing loop" ?

Сообщение Bizdelnick »

MiK13 писал(а):
05.11.2015 11:37
можно ли в тексте программы задавать уровень разный оптимизации для её разных частей?

Можно. Можно и выборочно вывод сообщений контролировать.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
Hephaestus
Сообщения: 3729
Статус: Многоуважаемый джинн...
ОС: Slackware64-14.1/14.2
Контактная информация:

Re: Что означает "note: containing loop" ?

Сообщение Hephaestus »

yoshakar писал(а):
05.11.2015 10:52
Компилятор с -Wall не даёт ложных срабатываний.
Что есть "ложное срабатывание" в данном случае?
Выдача лишнего ворнинга или, наоборот, отсутствие нужного? Или и то, и другое?
Вот что касается "отсутствия ворнинга", то замечено (не мной), что lint обнаруживает то, что -Wall пропускает.
Об этом упоминается в книге по Си и у меня нет оснований в этом сомневаться.
Если при этом оказывается, что более строгая проверка "подцепляет лишнее", ну что ж, возможно. Затрудняюсь рассудить, где здесь "золотая середина".
Пускай скрипят мои конечности.
Я - повелитель бесконечности...
Мой блог
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Что означает "note: containing loop" ?

Сообщение Bizdelnick »

yoshakar писал(а):
05.11.2015 10:52
Компилятор с -Wall не даёт ложных срабатываний. Там есть пара-тройка дурацких предупреждений, которые лчно я отключаю - они не дают пользоваться некоторыми полезными фичами языка

Можно полюбопытствовать, что это за фичи языка, которыми компилятор с -Wall не даёт пользоваться?
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
bormant
Сообщения: 1354

Re: Что означает "note: containing loop" ?

Сообщение bormant »

MiK13 писал(а):
05.11.2015 11:37
Что забавно, если заменить endl на '\n', то баг опять перестает проявляться.

В этом случае результирующий цикл по мнению оптимизатора такой:

Код: Выделить всё

    for (int i = 0; i != -294967296; i += 1000000) {
        std::cout << i << '\n';
    }
в ассемблерном выводе условие продолжения цикла выглядит так:

Код: Выделить всё

cmpl    $-294967296, %ebx
jne    .L3
Спасибо сказали:
yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: Что означает "note: containing loop" ?

Сообщение yoshakar »

Hephaestus писал(а):
05.11.2015 11:49
Что есть "ложное срабатывание" в данном случае?
Выдача лишнего ворнинга или, наоборот, отсутствие нужного?
Выдача лишнего. Просто это весьма чёткая граница между тем, где кончаются предупреждения компилтора, и начинается собственно статический анализ кода. А где находится "золотая середина" вопрос сложный. Некоторые считают, что даже мизерный процент ворнингов-совсем-не-по-делу - плохо. Я больших проектов на C(++) не писал, но для себя использую в первую очередь для проверки кода на переносимость чисто из эстетических соображений).
Спасибо сказали:
yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: Что означает "note: containing loop" ?

Сообщение yoshakar »

Bizdelnick писал(а):
05.11.2015 12:01
Можно полюбопытствовать, что это за фичи языка, которыми компилятор с -Wall не даёт пользоваться?
Например, наличие в операторе switch на enum'е веток не для всех значений енама. Типа такого:

Код: Выделить всё

enum my_enum {
    do1,
    do2,
    do_nothing,
    do_something
};

int do_work(enum my_enum e) {
    switch(e) {
    case do1: printf("1\n"); break;
    case do2: printf("2\n"); break;
    }
    return 9;
}
Необязательность ветки default в операторе switch - это же фича языка?
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Что означает "note: containing loop" ?

Сообщение Bizdelnick »

Ну так правильно, потому что в 99% случаев это ошибка. Лучше перебдеть, чем недобдеть. Да и с точки зрения читаемости кода лучше добавить пустой default, чтобы было видно, что ничего делать не надо, так и задумано.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Ответить