Porém, porque em C++ esse mesmo código é compilável? Isto é, porque no g++ é possível e no gcc não é possível? Os padrões das duas linguagens são diferentes até mesmo nesses aspectos?
Note que uma declaração, para ser válida, é composta por pelo menos uma declaration-specifiers e que este, é composto por, dentre outros, type-specifier (especificação de tipo). E aí, o que temos a respeito de especificadores de tipo é:
6.7.2 - Type specifiers
type-specifer:
void
char
short
int
long
float
double
signed
unsigned
unsigned
_Bool
_Complex
atomic-type-specifier
struct-or-union-specifier
enum-specifier
typedef-name
As últimas duas linhas respondem sua pergunta. enum-specifer é definido em 6.7.2.2 e tem a forma:
Ou seja, para que em C11 você faça uma declaração de uma enum válida, você precisa incluir a keyword enum. Caso não queira fazer isso, tem que recorrer à typedef-name, que é definida em 6.7.8.
Enzo Ferber
[]'s
$ indent -kr -i8 src.c
"(...)all right-thinking people know that (a) K&R are _right_ and (b) K&R are right."
- linux/Documentation/CodingStyle - TORVALDS, Linus.
No caso (1), dentro do bloco você não tem acesso a uma referência para essa enumeração. No caso (2) sim. Com enumerações é complicado de visualizar, então considere este exemplo com uma estrutura para lista encadeada:
Se tentar compilar, irá ver um erro: "unknown type name Node". Isso porque no momento que o parser encontra o identificar Node, ele ainda não foi definido (não está na tabela de símbolos). Portanto erro. Considere agora o segundo exemplo:
Desta vez, você declarou um "protótipo" da estrutura para incluir o nome da lista de símbolos do compilador. Portanto, ele sabe da existência de uma struct __node (que será definida em algum ponto futuro da unidade de compilação) e gera uma entrada pra ela.
Deu pra entender?
Enzo Ferber
[]'s
$ indent -kr -i8 src.c
"(...)all right-thinking people know that (a) K&R are _right_ and (b) K&R are right."
- linux/Documentation/CodingStyle - TORVALDS, Linus.
No caso (1), dentro do bloco você não tem acesso a uma referência para essa enumeração. No caso (2) sim. Com enumerações é complicado de visualizar, então considere este exemplo com uma estrutura para lista encadeada:
O'que seria essa "referência"?
Desculpe a pergunta, mas é que iniciei...ou melhor...reiniciei meus estudos em C a pouco tempo
8. Re: Problemas com enum em C [RESOLVIDO]
EnzoFerberusa FreeBSD
Post recolhido
Enviado em 19/06/2018 - 20:43h
isaak escreveu:
O'que seria essa "referência"?
Desculpe a pergunta, mas é que iniciei...ou melhor...reiniciei meus estudos em C a pouco tempo
Quando você declara uma struct, você está definindo um tipo de dados novo (um tipo de dados composto). Esse tipo de dados só é complemente definido após o fim do bloco (o }; que fecha a struct). typedef faz um "alias" (tipo um atalho) para o tipo. Portanto, se você não terminou de especificar o tipo, não pode fazer um atalho pra ele.
É como tentar criar um atalho para um arquivo no seu computador que ainda não existe.
E, claro, no padrão C11, que vai te explicar formalmente o que são typedefs, declarações e structs como novos tipos de dados.
A "referência" que eu disse é um tipo de dados nas tabelas internas do compilador, e talvez tenho sido vaga demais. Visto que um compilador possui diversas fases e diversas tabelas internas (sendo uma delas, a tabela de símbolos), essa "referência" é apenas uma lista de tipos válidos na unidade de compilação.
Observação: Não sou, nem de muito longe, especialista em compiladores. Só curioso mesmo.
Enzo Ferber
[]'s
$ indent -kr -i8 src.c
"(...)all right-thinking people know that (a) K&R are _right_ and (b) K&R are right."
- linux/Documentation/CodingStyle - TORVALDS, Linus.
9. Re: Problemas com enum em C [RESOLVIDO]
EnzoFerberusa FreeBSD
Post recolhido
Enviado em 19/06/2018 - 22:51h
Como dito anteriormente, eu sou bastante curioso. Apesar de saber como funciona (bem superficialmente), estou dando uma lida no C11 pra explicar melhor.
De acordo com o padrão, 6.7.2 Type specifiers, parágrafo 8, a presença de uma lista de declarações dentro de um bloco precedido pela palavra chave struct (com ou sem identificador) define um novo tipo na unidade de compilação, e este tipo é incompleto até que } seja encontrado. Além disso, sua pergunta (muito pertinente) sobre a diferença de presença de identificadores logo após enum/struct:
// caso 1 - estrutura definida pelo identificador `ident`, cria um novo tipo `struct ident`
struct ident {
int foo, bar;
};
// caso 2 - estrutura anônima
struct {
int a, b, c;
};
O segundo caso é formalmente chamado de estrutura anônima, e a definição e exemplo oficial são encontrados nos parágrafos 13 e 19 da seção 6.7.2, respectivamente.
Então:
typedef struct {
int a, b, c;
} MyStruct;
faz um alias para um tipo especificado pela definição da estrutura anônima struct { int a, b, c; };. É interessante observar que mesmo nesse tipo de definição, o alias para a estrutura anônima só pode ser feito APÓS a definição completa da estrutura (após o } final), permanecendo a validade da sintaxe para typedef:
typedef [tipo] [alias_name]
No caso, [tipo] é uma definição de uma struct em várias linhas, mas ainda assim é uma definição de tipo. Mais sobre o funcionamento/sintaxe de typedef pode ser encontrado na seção 6.7.8.
Quanto à minha "referência": dá uma olhada na seção 6.7.2.3 - Tags. Especificamente, os exemplos que vão te interessar estão nos parágrafos 9 e 10.
Enzo Ferber
[]'s
$ indent -kr -i8 src.c
"(...)all right-thinking people know that (a) K&R are _right_ and (b) K&R are right."
- linux/Documentation/CodingStyle - TORVALDS, Linus.