2016-09-04 8 views
-7

Недавно я начал использовать CLang для компиляции встроенных программ C++ ARM.Почему моя программа на C++ сбой, когда я забываю оператор return, а не просто возвращаю мусор?

До этого я использовал GCC и C, почти исключительно для встроенных работ.

Я заметил, что когда у меня есть метод, который возвращает значение, и я забыл оператор return, ядро ​​программы сбрасывает. На одном из драйверов устройства нет ошибки, кроме «msleep error -1». Это на FreeBSD.

Я бы ожидал, что забывание оператора return приведет к возврату мусора из функции, а не к дампу ядра.

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

Что происходит?

т.д .:

bool MyClass::DummyFunc() { 
    <do some stuff and forget the return value>  
} 

В другом месте:

if(pMyObj->DummyFunc()) { 
    print ("Hey, it's true!\n"); 
} else { 
    print ("Darn, it's false!\n"); 
} 

Этот код не должен врезаться, независимо от возвращаемого значения.

+2

Вы должны подумать о компиляции с использованием -Wall или -Wreturn-type, если вы склонны совершать такую ​​ошибку. – kfsone

ответ

3

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

Оттекание конца функции эквивалентно возврату без значения; это приводит к непредсказуемому поведению в функции значения возвращающих C++11 Draft pg 136

Мой опыт работы с лязгом было то, что компилятор будет рассматривать случаи «неопределенного поведения», как не будет и оптимизировать на пути. Что является законным, поскольку поведение не определено. Часто clang вместо этого выдает незаконную инструкцию вдоль пропущенного пути, так что код будет сбой, если произойдет «невозможное», что, вероятно, будет иметь место здесь. Фактически, компилятор мог бы определить, что вызов DummyFunc() приводит к неопределенному поведению и, следовательно, не может произойти, и вместо этого начать оптимизацию вызовов вызывающих тел.

НКУ далеко «дружелюбнее» и пытаются создать что-то хорошее, например, возвращение 0.

Примечания оба компилятора является правильным и производит правильный код в соответствии со стандартом.

+0

Это * интересный * выбор дизайна ... Это может объяснить нечетные обратные трассировки, которые я видел в GDB. Благодарю. – NXT

+0

В LLVM есть серия сообщений в блогах об этом выборе - http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html. – Brian

+0

Я не вижу, как это «_interesting_», если «_interesting_» вы имеете в виду как-то необычно или странно. Опять же, вам нужно пройти курс по абстрактным языкам, потому что вы принципиально не понимаете, что значит скомпилировать программу, написанную в одном. –

4

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

стекания конец функции эквивалентно возврату, без значения; это приводит к неопределенному поведению в возвращающей значение функции .

Это C++, когда вы делаете что-то неопределенное, вы должны ожидать, чтобы он разбил ваш компьютер и съел вашу прачечную, если в реализации не сказано иначе.

+1

Вы можете использовать N4140 или N3936, которые являются свободно доступными документами и идентичны опубликованному стандарту, кроме незначительных редакционных изменений и исправлений опечаток –

+2

@NXT Из этого замечания я не уверен, что вы отрицаете смысл неопределенного поведения, или если вам просто интересно, что это происходит в недрах Кланга. Если это последний, вам, возможно, повезло бы открыть новый вопрос, который делает это намерение понятным, с шагами по воспроизведению поведения в наших собственных системах. –

3

Я бы ожидал, что забывание оператора return приведет к возврату мусора из функции, а не к дампу ядра.

Что происходит?

Ваши ожидания ошибочны, это то, что происходит.

Компилятор — невероятно сложная машина — может предположить, что ваша функция возвращает значение, потому что вы пообещали, что это так.

Тогда вы нарушили это обещание.

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

Есть почти бесконечные способы, которыми это может сломаться, поскольку в процессе преобразования вашего кода на C++ в хорошо оптимизированную программу, читаемую вашим компьютером, компилятор делает серию чрезвычайно сложных оптимизаций, и любой из них могут быть разбиты пополам нарушением правил стандарта. Попытка определить, что именно произошло на какой-либо конкретной перспективе вашей программы потребует следующих знаний:

  • CPU марку, модели и версии
  • операционной системы марки, модели и версии
  • компилятора грим, модели и версий
  • все флаги компилятора
  • 10-летний опыт работы с исходным кодом компилятора
  • машины времени, чтобы проверить состояние каждого бита памяти в вашем компьютере во время вашего пр ogram.

Это действительно не стоит.

К счастью, в некоторых случаях, мы можем дополнительно рационализировать об этом случае, не предавая абстракцию, например, рассмотрим, что происходит, когда ты обещал бы вернуть std::string, но не сделали этого, а потом, что не существует std::string выходит за рамки. Деструктор вызывается на случайный вздор, и это не будет хорошо.

+0

Я возвращаюсь. Не имеет значения, какова ценность на самом деле. – NXT

+1

@NXT: Нет никакой ценности. Вы ничего не вернули. –

+0

@NXT Ваши допущения ошибочны. –

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

  • Нет связанных вопросов^_^