2014-01-17 1 views
7

цитаты из стандарта 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 есть ошибка?

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

+0

выход 2 с gcc 4.4.7 – tristan

+0

Проверьте мой ответ в другом потоке, особенно ссылку на обсуждение списка рассылки GCC: http://stackoverflow.com/a/19807355/1546653 Мне очень хотелось бы видеть это тоже выяснилось. – tab

+1

Пример, который вы дали вначале: это из стандарта? Это не похоже на пример того, что говорит стандарт? Я думаю, что стандарт говорит, что если вы делаете «main», «u.s1.m = 5», то компилятор ДОЛЖЕН предполагать, что «u.s2.m» изменился; но если вы передадите указатели на «u.s1» и «u.s2» вокруг, это совсем другое дело. –

ответ

3

Главное, что ваше изменение (перемещение соединения вверх) не меняет определения функции foo. Он по-прежнему является функцией, которая получает несвязанные указатели. В вашем примере переданные указатели связаны друг с другом, в других местах это может быть другим. Цель компилятора - служить наиболее общему случаю. Тело функции отличается после изменения, и непонятно, почему.

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

+0

Я больше разбираюсь в стандарте, заявляющем декларацию о союзе, видимость нарушает код – Ivan

+1

Стандарт говорит о союзах, а не о чем-то другом. У вашего 'foo' нет никакого союза ... Эти вещи не связаны. –

+0

@ Ivan Я понимаю, насколько сложно понять причину проблемы. Что означает Кирилл, так это то, что даже если объединение видимо, компилятор не может гарантировать, что объекты структуры 'p1' и' p2' обязательно являются частью объединения для всех вызовов 'foo'. Другими словами, насколько компилятор может сказать из объявления 'foo', два объекта структуры, переданные как формальные параметры, полностью не связаны. Если бы вы передали объект объединения самому себе функции, получилось бы иначе. В моем случае компилятор полностью оптимизирует вызов функции с вашим кодом. –

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

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