цитаты из стандарта C99:Исключения строгого правила наложения спектров в C от 6.5.2.3 Структуры и членов объединения
6.5.2.3
5 Особая гарантия делаются для того, чтобы упростить использование союзов : если объединение содержит несколько структур, которые имеют общую начальную последовательность (см. ниже), и если объект объединения в настоящее время содержит одну из этих структур, разрешено проверять общую начальную часть любого из них в любом месте, где декларация полный вид объединения виден. Две структуры имеют общую начальную последовательность, если соответствующие члены имеют совместимые типы (а для битовых полей - одинаковые ширины) для последовательности из одного или нескольких начальных элементов.
Существует пример для этого случая:
// The following code is not a valid fragment because
// the union type is not visible within the function f.
struct t1 { int m; };
struct t2 { int m; };
int f(struct t1 *p1, struct t2 *p2)
{
if (p1->m < 0)
p2->m = -p2->m;
return p1->m;
}
int g()
{
union
{
struct t1 s1;
struct t2 s2;
} u;
/* ... */
return f(&u.s1, &u.s2);
}
Я добавил несколько изменений:
#include <stdio.h>
struct t1 { int m; };
struct t2 { int m; };
union u
{
struct t1 s1;
struct t2 s2;
};
int foo(struct t1 *p1, struct t2 *p2)
{
if (p1->m)
p2->m = 2;
return p1->m;
}
int main(void)
{
union u u;
u.s1.m = 1;
printf("%d\n", foo(&u.s1, &u.s2));
}
Как вы можете видеть, что я переехал заявление профсоюза снаружи, так что будет видно в обув(). Согласно комментарию от стандарта, это должно было сделать мой код правильным, но похоже, что строгий псевдоним все еще нарушает этот код для clang 3.4 и gcc 4.8.2.
Вывод с -O0:
Вывод с -O2:
для обоих составителей.
Так что мой вопрос:
является C действительно полагается на декларации союза, чтобы решить, если некоторые структуры исключение строгого правила наложения спектров? Или у gcc/clang есть ошибка?
Мне кажется, что это действительно сломано, потому что даже если функция и объединение объявлены в одном заголовке, это не гарантирует, что объединение видимо в блоке перевода с телом функции.
выход 2 с gcc 4.4.7 – tristan
Проверьте мой ответ в другом потоке, особенно ссылку на обсуждение списка рассылки GCC: http://stackoverflow.com/a/19807355/1546653 Мне очень хотелось бы видеть это тоже выяснилось. – tab
Пример, который вы дали вначале: это из стандарта? Это не похоже на пример того, что говорит стандарт? Я думаю, что стандарт говорит, что если вы делаете «main», «u.s1.m = 5», то компилятор ДОЛЖЕН предполагать, что «u.s2.m» изменился; но если вы передадите указатели на «u.s1» и «u.s2» вокруг, это совсем другое дело. –