Есть ли какой-либо флаг компилятора, который я мог бы использовать в приведенном ниже коде, чтобы сообщить предупреждение о UB? - PullRequest
0 голосов
/ 24 мая 2018

Я не очень знаком с компилятором GCC, и я пытаюсь запустить код, используя два исходных файла в wandbox .Давайте начнем с первого кода, используя основной файл (по умолчанию) и второй исходный файл с именем other.cc, следующим образом:

основной файл

#include <iostream>
struct A {
    int i = 1;
    static const int k = 1;
};
extern A a;    // The object a is defined in other.cc

int main() {
    std::cout << a.i << '\n';
    std::cout << a.k << '\n';
}

other.cc

struct A {
    int i = 1;
    static const int k = 1;
};
A a{2};

Обратите внимание, что мне нужно вставить имя файла other.cc в поле Параметры компилятора , слева от Wandbox,для того, чтобы этот файл был скомпилирован и связан с окончательным объектным файлом.Запустив этот код, я получу числа 2 и 1, напечатанные ниже, и они верны.

2
1

Теперь, если я исключу файл other.cc из процессов компиляции и компоновки, удалив его имя из Параметры компиляции В поле я получаю сообщение об ошибке ссылки на элемент нестатических данных A::i, используемый в выражении

std::cout << a.i << '\n';

Если я затем удалю этот оператор изкод, он , по-видимому, работает нормально, потому что компилятор заменяет переменную a.k на ее постоянное значение 1 в оставшейся инструкции std::cout << a.k << '\n'; в main (), печатая 1. Но это считается неопределенным поведением,в соответствии с [basic.def.odr] / 10 и [intro.compliance] / 2 (2.3) .Обратите внимание на то, что «не требуется никакой диагностики», упомянутой в [basic.def.odr] /10.

Затем я пытаюсь заставить компилятор выдать ошибку в этом случае, используя некоторый флаг, который будетпредотвратить эту оптимизацию.Я уже пробовал с флагами -fkeep-static-consts и -fno-keep-static-consts, но безрезультатно.Есть ли другой флаг, который я мог бы использовать, чтобы избежать этого неопределенного поведения?

Я получил этот пример от этого обсуждения в C ++ std-обсуждение.

IЗнайте, что определение объекта a в первом файле решит проблему.Но это не то, что я ищу с этим странным примером.Я просто пытаюсь получить лучшее представление о том, как работают компиляторы в этих необычных обстоятельствах.

Ответы [ 2 ]

0 голосов
/ 24 мая 2018

Я думаю, что ответ на другой вопрос был бы более осветительным.Боязнь неопределенного поведения заключается в невозможности гарантировать одинаковые результаты во время выполнения при использовании разных компиляторов.Итак:

Разве мне не нужно сообщение об ошибке, чтобы гарантировать, что поведение во время выполнения не зависит от используемого компилятора? Нет. Необходимо рассмотреть два случая.

Первый случай: компилятор заменяет a.k значением 1.Поведение во время выполнения является ожидаемым результатом.

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

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

Если некоторые не находят этот ответ светящимся, я теперь вернусь к первоначальному вопросу, перефразировав его немного.

Есть ли какой-либо флаг, который я могу использовать для принудительного появления диагностического сообщения(ошибка или предупреждение), когда происходит такого рода нарушение правила с одним определением? Зависит от компилятора, но, вероятно, нет.Обратите внимание, что в [basic.def.odr] / 10 упоминается «диагностика не требуется», поэтому компилятору не требуется предоставлять диагностическое сообщение при возникновении данного конкретного нарушения.Почему бы и нет?Предположительно из-за вышеизложенного: либо сообщение будет запущено на более позднем этапе (т. Е. Связывание), либо намеченное поведение просвечивает.Нет смысла увеличивать бухгалтерию компилятора, поскольку в этом случае требуется ошибка / предупреждение.

0 голосов
/ 24 мая 2018

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

У компоновщика будет опция, которая делаетэто не удастся, и вы можете передать параметры компоновщику через большинство компиляторов, включая g++.Я могу заставить его работать с gcc следующим образом:

g++ -std=c++11 -Xlinker --require-defined=a main.cpp

, который выдает ошибку

/usr/bin/ld: required symbol `a' not defined
collect2: error: ld returned 1 exit status

Вы не просили об этом, но clang++ немного проще:

clang++ -std=c++11 -u a main.cpp 

и более многословно, тоже:

Undefined symbols for architecture x86_64:
  "a", referenced from:
     -u command line option
     (maybe you meant: __ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m, _main , __ZNSt3__111char_traitsIcE3eofEv , __ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_ , __ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_c , ___clang_call_terminate , __ZNSt3__111char_traitsIcE11eq_int_typeEii )
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Дайте этому шанс.

...