Почему компоновщик не выдаст ошибку в коде ниже? - PullRequest
0 голосов
/ 29 мая 2018

Я нашел пример ниже здесь .Очевидно, что комментарий во фрагменте был неверным, поскольку переменная S::x используется в выражении &S::x.

struct S { static const int x = 1; };
void f() { &S::x; } // discarded-value expression does not odr-use S::x
int main(){
    f();
}

См. живой пример

IЯ понимаю, что компилятору не нужно выдавать такую ​​ошибку, потому что [basic.def.odr] / 10 говорит: «Диагностика не требуется».Но почему компоновщик не выдаст ошибку о неопределенной переменной S::x, как это происходит в приведенном ниже коде?

#include<iostream>
struct S { static const int x = 1; } s;

int main() {
    std::cout << &s.x << '\n';
}  

См. живой пример .

Ответы [ 3 ]

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

Очевидно, что комментарий во фрагменте был неверным, так как переменная S::x используется в выражении &S::x.

И затем это выражение отбрасывается на битовый пол,&S::x; не используется ODR.Однажды вариант [basic.def.odr] параграфа 3 гласит (выделено жирным шрифтом):

Переменная x, имя которой выглядит как потенциально оцениваемое выражение ex, является odr-используется ex , если применение преобразования lvalue-to-rvalue в x не приводит к константному выражению, которое не вызывает никаких нетривиальных функций и, если x является объектом, exявляется элементом набора потенциальных результатов выражения e, где либо преобразование lvalue-в-значение применяется к e, либо e является выражением отброшенного значения .

Раздел [expr], параграф 11, охватывает концепцию выражения отбрасываемого значения:

В некоторых контекстах выражение появляется только для его побочных эффектов.Такое выражение называется выражением отброшенного значения .Выражение вычисляется и его значение отбрасывается.Стандартные преобразования массива в указатель и функции в указатель не применяются.Преобразование lvalue-to-rvalue применяется тогда и только тогда, когда выражение является glvalue типа volatile-квалифицированным и является одним из следующих:

  • (выражение), где выражение является одним из следующихвыражения,
  • id-выражение,
  • подписка,
  • доступ к члену класса,
  • косвенное указание,
  • операция указателя на член,
  • условное выражение, где оба и третий операнд являются одним из этих выражений, или
  • выражение запятой, где правый операнд является одним из этих выражений.

Оператор &S::x; является выражением отбрасываемого значения, которое не требует преобразования lvalue в rvalue, поэтому преобразовывать нечего.С таким же успехом оператор может не существовать и, следовательно, не существует в том, что касается использования ODR.

Этот показатель можно изменить, указав S::x как volatile, а не const,и пытаясь сбросить S::x на битовый этаж:

struct S { static volatile int x; };
void f() { S::x; } // This discarded-value expression does odr-use S::x
int main(){
    f();
}

Выше компилируется (но с предупреждением об отброшенном выражении) с компилятором / компоновщиком GNU C ++ с использованием --std=c++03, но не компилируется /ссылка с использованием --std=c++11 или выше.C ++ 11 добавил совсем немного о работе абстрактной машины C ++.Несмотря на то, что S::x; остается выражением отброшенного значения, для того, чтобы S::x теперь было энергозависимым, требуется, чтобы компилятор применил преобразование lvalue-в-значение перед сбросом результата в битовый пол.

Изменение S::xв приведенном выше к &S::x и программа снова компилируется (но еще раз с предупреждением об отброшенном выражении).Несмотря на то, что S::x является изменчивым, это не адрес.

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

Но почему компоновщик не выдаст ошибку о неопределенной переменной S :: x, как это происходит в приведенном ниже коде?

Поскольку он просто оптимизирован!Выражение, результат которого никогда не используется и не имеет побочных эффектов, будет просто проигнорировано.И то, что было проигнорировано, не должно быть связано. Нет просто кода, который ссылается на переменную, даже если адрес был взят, но затем не используется.

Как видно из примера wandbox, компилятор выдаетправильная диагностика: «результат выражения не используется».

Код, который не используется, позже не приведет к ошибкам компоновщика;)

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

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

Вы спрашиваете:

[Почему] компоновщик не выдает ошибку?

, говоря:

[basic.def.odr] / 10 говорит: «Диагностика не требуется»

Вы отвечаете на свой вопрос в «Диагностика не требуется» .Несоответствие правилу odr: Undefined Behavior , компоновщик может вызвать ошибку или создать 4D версию Tetris , и спецификации все равно будут в порядке!


И чтобы уточнить про &S::x использование или одра x:

Переменная x, имя которой появляется в качестве потенциально вычисляемого выражения ex равно odr-used на ex, если только применение преобразования lvalue-to-rvalue в x не приводит к константному выражению , которое не вызывает никаких нетривиальных функций и, если x является объектом, ex - это элемент набора потенциальных результатов выражения e, где к e применяется либо преобразование lvalue-в-значение, либо e - выражение отброшенного значения.

Адресобъекта никогда не является постоянным выражением.S::x используется odr в &S::x.

Для обоснования этого последнего утверждения:

[expr.const]/6

КонстантаВыражение является либо основным выражением константы glvalue, которое относится к объекту, который является разрешенным результатом постоянного выражения (как определено ниже), либо выражением константы основного значения, значение которого удовлетворяет следующим ограничениям [...]

и

[expr.const]/2.7

2) Выражение e является выражением основной константы , если только оценкаиз e, , следуя правилам абстрактной машины , будет вычислять одно из следующих выражений:
[...]
2.7) преобразование lvalue-в-значение, если оно не являетсяприменяется к

(не применяется ни один из следующих пунктов:)

2.7.1) к энергонезависимому типу glvalue целочисленного или перечислимого типа, который относится к полномуобъект volatile const с предшествующей инициализацией, инициализированный константным выражением,или
2.7.2) энергонезависимое glvalue, которое относится к подобъекту строкового литерала, или
2.7.3) энергонезависимое glvalue, которое относится к энергонезависимому объекту, определенному с помощью constexpr, или чтоотносится к неизменяемому подобъекту такого объекта, или
2.7.4) к энергонезависимому значению литерального типа, которое относится к энергонезависимому объекту, время жизни которого началось в пределах оценки e;

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