OVH Cloud OVH Cloud

structure, typedefs, C et C++

4 réponses
Avatar
Alexis Nikichine
Bonjour,

j'ai l'unité de compilation suivante:

typedef struct b_
{}
b;

struct a
{
b* b;
};

qui compile très bien en C:

$ gcc -c struct_c.c

mais par contre, en C++:

$ g++ -c struct_c.c
struct_c.c:7: error: declaration of `b*a::b'
struct_c.c:3: error: changes meaning of `b' from `typedef struct b_ b'

Quoi qu'est-ce dont, et pourquoi ?

On a le droit en C, mais pas en C++ ? Peut-être parce que en C++, on a
une notion de code "à l'intérieur d'une classe", et qu'il peut être
gênant de masquer un nom de type par un nom de membre ?

Alors pourquoi Comeau (online) l'accepte-t-il en mode C++ ?

Autres données: ça compile très bien avec Visual C++ 6 (et heureusement,
car ce genre de définition est utilisé dans des headers DirectX). Par
contre, en mode C, Comeau rejette le code, car apparemment, on ne peut
pas avoir de struct vide en C, Ce qui n'est pas tout à fait l'avis de
gcc qui n'émet qu'un warning:

$ gcc -c -pedantic struct_c.c
struct_c.c:3: warning: struct has no members

Si quelqu'un peut m'aider à débroussailler ça... merci à lui :-)

Alexis


--
Un certain domaine est free.

4 réponses

Avatar
Gabriel Dos Reis
Alexis Nikichine writes:

| Bonjour,
|
| j'ai l'unité de compilation suivante:
|
| typedef struct b_
| {}
| b;
|
| struct a
| {
| b* b;
| };

Invalide en C++

| qui compile très bien en C:
|
| $ gcc -c struct_c.c
|
| mais par contre, en C++:
|
| $ g++ -c struct_c.c
| struct_c.c:7: error: declaration of `b*a::b'
| struct_c.c:3: error: changes meaning of `b' from `typedef struct b_ b'
|
| Quoi qu'est-ce dont, et pourquoi ?


Le compilateur a tout dit : en C++, les noms utilisés dans la
définition d'une classe sont évalués deux fois, une fois pendant la
définition et une fois l'accolade fermante vue. Si les deux
évaluations donnent des significations différentes aux noms, alors ton
programme est invalide.

|
| On a le droit en C, mais pas en C++ ?

Oui. En C, les gens aiment écrire ça, je ne sais pas pourquoi.

| Peut-être parce que en C++, on
| a une notion de code "à l'intérieur d'une classe", et qu'il peut être
| gênant de masquer un nom de type par un nom de membre ?

Oui.

|
| Alors pourquoi Comeau (online) l'accepte-t-il en mode C++ ?

En mode strict ? Note que le programme est invalide mais le
compilateur n'est pas obligé de te le dire. GCC a toujours donné le
message d'erreur.

|
| Autres données: ça compile très bien avec Visual C++ 6 (et
| heureusement, car ce genre de définition est utilisé dans des headers
| DirectX). Par contre, en mode C, Comeau rejette le code, car
| apparemment, on ne peut pas avoir de struct vide en C, Ce qui n'est

C'est vari aussi. C a toujours rejeté les structures sans membre.

| pas tout à fait l'avis de gcc qui n'émet qu'un warning:
|
| $ gcc -c -pedantic struct_c.c
| struct_c.c:3: warning: struct has no members
|
| Si quelqu'un peut m'aider à débroussailler ça... merci à lui :-)
|
| Alexis
|
|
| --
| Un certain domaine est free.
|

--
Gabriel Dos Reis

Avatar
Alexis Nikichine
Gabriel Dos Reis wrote:
Alexis Nikichine writes:

| typedef struct b_
| {}
| b;
|
| struct a
| {
| b* b;
| };

Invalide en C++

| $ g++ -c struct_c.c
| struct_c.c:7: error: declaration of `b*a::b'
| struct_c.c:3: error: changes meaning of `b' from `typedef struct b_ b'

Le compilateur a tout dit : en C++, les noms utilisés dans la
définition d'une classe sont évalués deux fois, une fois pendant la
définition et une fois l'accolade fermante vue.


Ok; faire gaffe aux numéros de lignes qu'indique gcc, donc.

Si les deux
évaluations donnent des significations différentes aux noms, alors ton
programme est invalide.


Alors, juste pour être sûr que je comprend, ce programme :

struct b
{};

struct a
{
struct b* b;
};

est valide, car ce n'est pas "b" utilisé comme type dans la définition
de la struct a, mais "struct b", et ainsi "b", membre de a, n'entre pas
en conflit avec "struct b" au moment de l'accolade fermante ?



| On a le droit en C, mais pas en C++ ?

Oui. En C, les gens aiment écrire ça, je ne sais pas pourquoi.


Ah ! Ces programmeurs C...

| Alors pourquoi Comeau (online) l'accepte-t-il en mode C++ ?

En mode strict ?


Affirmatif.

Note que le programme est invalide mais le
compilateur n'est pas obligé de te le dire. GCC a toujours donné le
message d'erreur.


Ah ? C'est une question de "qualité de l'implémentation" qu'un
compilateur me fasse remarquer que mon programme est invalide ? La norme
n'est-elle pas parsemée de "diagnostic required" un peu partout ?

En tout cas, merci,

Alexis

--
Un certain domaine est free.

Avatar
Gabriel Dos Reis
Alexis Nikichine writes:

[...]

| > Si les deux
| > évaluations donnent des significations différentes aux noms, alors ton
| > programme est invalide.
|
| Alors, juste pour être sûr que je comprend, ce programme :
|
| struct b
| {};
|
| struct a
| {
| struct b* b;
| };
|
| est valide, car ce n'est pas "b" utilisé comme type dans la définition
| de la struct a, mais "struct b", et ainsi "b", membre de a, n'entre
| pas en conflit avec "struct b" au moment de l'accolade fermante ?

Oui. La raison est toute simple (bien que tordue) : "struct b" ne
change pas de signification avant le "{", ni après la déclaration de
a::b. Mais par contre ceci est invalide

struct b { } ;

struct a {
struct b* a;
struct b { };
};

mais GCC ne te le dira pas. Par contre, si tu essaies ceci

struct b { };

struct a {
b* x;
struct b { };
};

il râlera. Tu peux faire un bug report :-)


| > | On a le droit en C, mais pas en C++ ?
| >
| > Oui. En C, les gens aiment écrire ça, je ne sais pas pourquoi.
|
| Ah ! Ces programmeurs C...
|
| > | Alors pourquoi Comeau (online) l'accepte-t-il en mode C++ ?
| > En mode strict ?
|
| Affirmatif.
|
| > Note que le programme est invalide mais le
| > compilateur n'est pas obligé de te le dire. GCC a toujours donné le
| > message d'erreur.
|
| Ah ? C'est une question de "qualité de l'implémentation" qu'un
| compilateur me fasse remarquer que mon programme est invalide ? La
| norme n'est-elle pas parsemée de "diagnostic required" un peu partout ?

Par défaut, quand la norme dit « ill-formed », ça veut dire que la
compilateur doit broncher. Mais si elle ajoute « no diagnostic
required », ça veut dire que le compilateur n'est pas obligé de
broncher.

3.3.6/1
[...]
2) A name N used in a class S shall refer to the same declaration
in its context and when re-evaluated in the completed scope of
S. No diagnostic is required for a violation of this rule.

3) If reordering member declarations in a class yields an alternate
valid program under (1) and (2), the program is ill-formed, no
diagnostic is required.

-- Gaby
Avatar
Fabien LE LEZ
On Wed, 15 Dec 2004 18:55:31 +0100, Alexis Nikichine
:

est valide


... mais fortement déconseillé tout de même.


--
;-)