Return {0} из функции из C?

Я получил следующее несоответствие между компиляцией как 'C' vs. компиляция как 'С++'

struct A {
  int x;
  int y;
};

struct A get() {
  return {0};      
}

При компиляции как "С++" все идет хорошо. Однако при компиляции как "C"; я получаю:

ошибка: ожидаемое выражение

который я могу исправить, выполнив:

return (struct A){0};      

Тем не менее, мне интересно, откуда эта разница. Может ли какая-либо точка ссылаться на язык, где происходит эта разница?

Ответы

Ответ 1

Оба используют совершенно разные механизмы, один из которых является С++ 11-специфичным, другой из которых является C99-специфичным.

Первый бит,

struct A get() {
  return {0};
}

зависит от [stmt.return] (6.6.3 (2)) в С++ 11, в котором говорится, что

(...) Оператор return с бин-init-list инициализирует объект или ссылку, возвращаемую функцией, путем инициализации списка-списка из указанного списка инициализаторов. [Пример:

std::pair<std::string,int> f(const char *p, int x) {
  return {p,x};
}

- конец примера]

Этот фрагмент не существует в C (и С++ до С++ 11), поэтому компилятор C не может его обработать.

С другой стороны,

struct A get() {
  return (struct A){0};
}

использует функцию C99, называемую "составные литералы", которая не существует в С++ (хотя некоторые компиляторы С++, особенно gcc, предоставляют ее как расширение языка, gcc предупреждает об этом с помощью -pedantic). Семантика подробно описана в разделе 6.5.2.5 стандарта C99; денежная цитата

4 Постфиксное выражение, состоящее из имени типа в скобках, за которым следует список инициализаторов, заключенных в скобки, является сложным литералом. Он предоставляет неназванный объект, значение которого задается в списке инициализаторов. (сноска 80)

80) Обратите внимание, что это отличается от литого выражения. Например, cast задает преобразование только для скалярных типов или void, а результат литого выражения не является lvalue.

Таким образом, в этом случае (struct A){0} является неназванным объектом, который копируется в возвращаемое значение и возвращается. (обратите внимание, что современные компиляторы вернутся к этой копии, поэтому вам не нужно опасаться накладных расходов во время выполнения)

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