2015-01-11 1 views
9

Я смотрел в ун-традиционным способом достижения STRUCT «полиморфизм» в пре-C11 С. Допустим, у нас есть 2 структур:объединение структур, разделяющих одни и те же первые члены

struct s1 { 
    int var1; 
    char var2; 
    long var3; 
}; 

struct s2 { 
    int var1; 
    char var2; 
    long var3; 
    char var4; 
    int var5; 
}; 

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

Теперь, я нашел следующую строку в стандарте C насколько C89:

Особая гарантия делаются для того, чтобы упростить использование союзов: Если объединение содержит несколько структур, которые разделяют общее начальная последовательность, и если объект объединения в настоящее время содержит одну из этих структур, разрешается проверять общую начальную часть любого из них. Две структуры имеют общую начальную последовательность, если соответствующие члены имеют совместимые типы для последовательности одного или нескольких начальных членов.

Он также утверждает следующее:

Указатель на накидной объекта, соответствующим образом отбрасываемой, указывает на каждый из его членов (или если член битовое поле, а затем в блок в который он проживает), и наоборот.

Теперь, если я создаю объединение этих двух структур:

union s2_polymorphic { 
    struct s1 base; 
    struct s2 derived; 
}; 

и использовать его таким образом:

union s2_polymorphic test_s2_polymorphic, *ptest_s2_polymorphic; 
struct s2 *ptest_s2; 
struct s1 *ptest_s1; 

ptest_s2_polymorphic = &test_s2_polymorphic; 

ptest_s2 = (struct s2*)ptest_s2_polymorphic; 

ptest_s2->var1 = 1; 
ptest_s2->var2 = '2'; 

ptest_s1 = (struct s1*)ptest_s2; 

printf("ptest_s1->var1 = %d\n", ptest_s1->var1); 
printf("ptest_s1->var2 = %c\n", ptest_s1->var2); 

Который компилируется и работает нормально, и дает на НКУ (GCC) 4.8.3 20140911, выход

ptest_s1->var1 = 1                
ptest_s1->var2 = 2 

Будет ли поведение корректно определено в соответствии с кавычками из приведенного выше стандарта?

+0

Возможно, я не понимаю, что вы здесь делаете, но в примере с 'union', а не' s2' (т. Е. 'Производный') теперь не дублирует содержимое' s1'? IE не должен содержать только лишние элементы? – abligh

+1

"* Будет ли поведение четко определено *" Я бы сказал: да. Что заставляет вас сомневаться в этом? – alk

+0

@abligh: и я могу не понимать ваш вопрос ... Что вы подразумеваете под «содержать только лишние элементы»? – Mints97

ответ

1

После некоторых исследований, я думаю, что у меня есть квалифицированный ответ на этот вопрос.

Приведенная цитата была из стандарта C89. C99 и C11 имеют это перефразировать так:

Особая гарантия делаются для того, чтобы упростить использование союзов: если объединение содержит несколько структур, которые имеют общую исходную последовательность (см ниже), и если объединение объект в настоящее время содержит одну из этих структур, разрешено проверять общую начальную часть любого из них в любом месте, где видна декларация завершенного типа объединения.

Последняя часть может быть истолкована, ИМХО, различными способами. Однако комитет оставил его как есть. По их словам, это означает, что проверка «общей начальной части» структур может быть сделана только только с использованием объекта типа union, который был объявлен содержащим их. Это очень хорошо продемонстрировано в this question.

Как насчет C89, который, кажется, позволяет то, что я пытался сделать? Ну, в компиляторе, совместимом с C89, да, это должно сработать.Однако это может и не понадобиться: я не знаю ни одного строгого C89-совместимого компилятора, который поддерживает строгий псевдоним, поэтому с ними проще просто сгруппировать структуры с общей начальной последовательностью для типов друг друга и постарайтесь не дать им разные настройки упаковки. Результат должен быть таким же.

+0

Учитывая, что заполненный тип профсоюза должен быть видимым, чтобы получить доступ к чему-либо через него, почему авторы Стандарта ничего не сказали о видимости завершенного типа профсоюза, если бы они не намеревались разрешить декларации профсоюзов «связывать» связанные типы как группу, которая должна допускать взаимный контроль общих членов друг друга? Я знаю, что авторам gcc не нравится это правило, и были бы лучшие способы достижения желаемого результата, но членство в видимом объединении - это средство, которое авторы Стандарта решили разрешить такую ​​семантику. – supercat

+0

Если Стандарт должен явно указывать указатель на любой тип, который должен быть отнесен к указателю на объединение, содержащее этот тип, при условии, что он используется только для доступа к соответствующему члену объединения или другим членам с общей начальной последовательностью, и если это что операции через два типа объединения, которые разделяют любые члены, могут быть псевдонимом, который может быть хорошим способом предложить надлежащую функциональность, но если один член профсоюза имеет более грубое выравнивание, чем другое, наведение указателя на слабо выровненный объект на объединение указатель вызовет UB, поскольку он не будет удовлетворять выравниванию соединения. – supercat

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