On-line: гостей 0. Всего: 0 [подробнее..]
Программисты всех стран, объединяйтесь!

АвторСообщение



ссылка на сообщение  Отправлено: 28.07.12 20:41. Заголовок: MS VC++ 2010: баг при определение вложенной структуры.


Неожиданно обнаружился следующий баг компилятора MS VC++ 2010, связанный с определением вложенной структуры. Также возможно (требуется проверка по стандарту С++) имеется баг и в компиляторе GCC 4.7.x.

Приведу сначала демонстрационный пример, иллюстрирующий сказанное.

 #include "stdafx.h" 
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
struct WithUnnamedUnion
{
enum { INT, FLOAT, CHAR } kind;
union
{
int m1;
float m2;
char m3;
};
};

struct WithUnnamedStruct
{
enum { INT, FLOAT, CHAR } kind;
struct
{
int m1;
float m2;
char m3;
};
};

std::cout << "sizeof( WithUnnamedUnion ) = "
<< sizeof( WithUnnamedUnion ) << std::endl;
std::cout << "sizeof( WithUnnamedStruct ) = "
<< sizeof( WithUnnamedStruct ) << std::endl;
return 0;
}


Сначала скажу о компиляторе GCC 4.7.x. Он не компилирует этот код, выдавая следующее сообщение об ошибке:


 цитата:
error: ISO C++ prohibits anonymous structs



То есть компилятор говорит, что анонимные структуры нельзя объявлять, хотя в стандарте С++ в самом начале раздела №9, посвященного классам, в описании грамматики указано, что имя класса может быть опущено. Поэтому надо еще уточнить, может быть где-нибудь далее в стандарте говорится, что имя можно опустить только в случае объявления анонимных объединений.

Но в отличии от GCC 4.7.x MS VC++ 2010 спокойно компилирует этот код и выдает следующий результат:


 цитата:
sizeof( WithUnnamedUnion ) = 8
sizeof( WithUnnamedStruct ) = 16



То есть компилятор MS VC++ рассматривает вложенную безымянную структуру как определение члена данных внешнего класса. То есть поступает так, как это делается для анонимных объединений, хотя анонимных структур в С++ нет в отличии от С.

Если же определению вложенной стурктуры присвоить имя, как показано в демонстрационном примере ниже

 #include "stdafx.h" 
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
struct WithUnnamedUnion
{
enum { INT, FLOAT, CHAR } kind;
union
{
int m1;
float m2;
char m3;
};
};

struct WithUnnamedStruct
{
enum { INT, FLOAT, CHAR } kind;
struct InnerStruct
{
int m1;
float m2;
char m3;
};
};

std::cout << "sizeof( WithUnnamedUnion ) = "
<< sizeof( WithUnnamedUnion ) << std::endl;
std::cout << "sizeof( WithUnnamedStruct ) = "
<< sizeof( WithUnnamedStruct ) << std::endl;
return 0;
}


где вложенной структуре присвоено имя InnerStruct, то уже оба компилятора компилируют этот код и выдают следующий результат:


 цитата:
sizeof( WithUnnamedUnion ) = 8
sizeof( WithUnnamedStruct ) = 4



Итак, похоже, что компилятор MS VC++ 2010 рассматривает структуры без имени аналогично анонимным объединениям, то есть делает их членами данных внешнего класса. С другой стороны, компилятор GCC 4.7.x запрещает использование безымянных структур, что требует проверки, соответствует ли этот запрет стандарту С++ или нет.

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 4 [только новые]





ссылка на сообщение  Отправлено: 28.07.12 20:42. Заголовок: Просмотрел стандарт ..


Просмотрел стандарт С и могу сказать, что язык С разрешает анонимные структуры как члены других структур. При этом члены этой структуры являются членами обрамляющей структуры. Поэтому в данном случае компилятор MS VC++ 2010 ведет себя по крайней мере в соответствии со стандартом С. Но все же не совсем в соответсвии с этим стандартом, так как вы не сможете обратиться к членам анонимной структуры. Этого не позволяет делать сам компилятор, в чем вы можете сами убедиться, попробовав в примере с неименованной структурой создать объект и присовить значение члену этой структуры. Поэтому получается какое-то половинчатое решение. С одной стороны, компилятор MS VC++ 2010 включает размер анонимной струкутры в подсчет размера обрамляющей структуры, с другой стороны, вы не можете обратиться к членам этой анонимной структуры.

Вот выдержка из стандарта С. Это параграф №13 раздела 6.7.2.1 "Structure and union specifiers":


 цитата:
13 An unnamed member of structure type with no tag is called an anonymous structure; an
unnamed member of union type with no tag is called an anonymous union. The members
of an anonymous structure or union are considered to be members of the containing
structure or union. This applies recursively if the containing structure or union is also
anonymous.



Теперь осталось внимательно почитать стандарт С++, чтобы дать полный "диагноз".

Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 20:43. Заголовок: Хотел бы уточнить св..


Хотел бы уточнить свое первое сообщение по этой теме. а то может сложиться неправильное понимание вопроса.

Итак, в С++ анонимных структур нет. Есть только анонимные объединения. Поэтому выдаваемый результат компилятором MS VC++ 2010 размера внешней структуры с неименованной внутренней структурой является на мой взгляд багом этого компилятора.

С другой стороны, вполне возможно, и это следует проверить, стандарт С++ разрешает определять неименованные структуры без декларатора. Тогда в этом случае имеется баг компилятора GCC 4.7.x, так как он не должен был выдавать ошибку компиляции при обнаружении неименованной структуры внутри другой структуры, а должен был просто игнорировать ее или выдать предупреждение, что вложенная структура не может быть использована.


Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 20:43. Заголовок: Похоже, что все-таки..


Похоже, что все-таки в С++ нельзя объявлять безымянные классы без декларатора. Соласно параграфу №3 раздела 7 Declarations стандарта С++:


 цитата:
3 In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (Clause 9) or enumeration (7.2), that is, when the decl-specifier-seq contains either a class-specifier, an elaboratedtype-specifier with a class-key (9.1), or an enum-specifier. In these cases and whenever a class-specifier or enum-specifier is present in the decl-specifier-seq, the identifiers in these specifiers are among the names being declared by the declaration (as class-names, enum-names, or enumerators, depending on the syntax). In such cases, and except for the declaration of an unnamed bit-field (9.6), the decl-specifier-seq shall introduce one or more names into the program, or shall redeclare a name introduced by a previous declaration.



То есть, например, такие два объявления, как

 struct {}; 

struct A
{
struct {};
};


являются некорректными, так как они не вводят имена в программу (за исключением самой структуры A). Правда в этом параграфе есть упущение: не упоминаются анонимные объединения. Но на самом деле анонимные объединения вводят имена своих членов в программу.
Тем не менее, интересно отследить, насколько этот параграф согласуется с описание классов в разделе 9.

Поэтому ставим диагноз, что все же, исходя из наличия приведенной мною информации, GCC 4.7.x не имеет бага, то есть его сообщение об ошибке вполне корректное, тогда как MS VC++ 2010 содержит явный баг, рассматривая в программе, написанной на С++, вложенную безымянную структуру аналогично анонимной структуре, как это имеет место в языке С, и в тоже время не позволяя обращаться к членам этой структуры.



Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 20:44. Заголовок: Оказывается, анонимн..


Оказывается, анонимные стурктуры в MS VC++ - это намеренное расширение языка разработчиками компилятора.

Вот ответ от Майкрософт:


 цитата:
Posted by Microsoft on 11.07.2012 at 16:39

Hi,
Thanks for reporting the issue.
Anonymous structure is Microsoft extension and is explained here: http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx. It says:

You can access the members of an anonymous structure as if they were members in the containing structure.

So the behavior is by design.



Я уже писал здесь на форуме в теме MS VC++ 2010: когда баг не является багом, а является расширением языка по поводу того, что порой имеется не баг, а расширение языка, и сам же забыл про свой совет в той теме - проверять код на строгое соответствие стандарту выбором соответствующей опции компилятора.

Действительно, если установить в свойствах проекта опцию "Отключить расширения языка", то приведенный мною ранее пример компилироваться не будет. Будет выдано сообщение компилятора об ошибке:


 цитата:
error C2467: недопустимое объявление анонимного "struct"

.

Я включу описание этого расширения языка уомпилятора MS VC++ 2010 в свою упомянутую здесь тему, которая как раз этому вопросу и посвящена.


Спасибо: 0 
ПрофильЦитата Ответить
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 3
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет