Problemas com enum em C [RESOLVIDO]

1. Problemas com enum em C [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 18/06/2018 - 21:28h


Por que na linguagem C não é possível declara um enum da seguinte maneira :


#include <stdio.h>
#include <string.h>

enum Gender{male, female, gay, flowing_gender};

struct __person{

char complete_name[256];
char cpf[12], rg[10];
Gender gender;

}person;

int main(void){

strncat(person.complete_name, "Cleinivaldo Sakrudi", 256);
strncat(person.cpf, "82834635005", 12);
strncat(person.rg, "412125304", 10);

person.gender=flowing_gender;

return 0;
}


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?


  


2. MELHOR RESPOSTA

Enzo de Brito Ferber
EnzoFerber

(usa FreeBSD)

Enviado em 19/06/2018 - 16:00h

Acrescentando à resposta anterior:

É possível fazer como você estava fazendo, entretanto, você deve ser explicito:


enum Gender{male, female, gay, flowing_gender};

struct __person{

char complete_name[256];
char cpf[12], rg[10];
enum Gender gender;

}person;


É perfeitamente válido. typedef serve para definir um tipo de dados, usando enum Gender você especifica exatamente o tipo de Gender (como tipo enum).

EDIT: A typedef declaration does not introduce a new type, only a synonym for the type so specified.

*

Já que mencionou o padrão, no C11(http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf):

Primeiro, sobre declarações (6.7)


6.7 Declarations

declaration:
declaration-specifiers init-declarator-listopt ;
static_assert-declaration

declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
function-specifier declaration-specifiersopt
alignment-specifier declaration-specifiersopt

init-declarator-list:
init-declarator
init-declarator-list , init-declarator

init-declarator:
declarator
declarator = initializer


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:


enum-specifier:
enum identifieropt { enumerator-list }
enum identifieropt { enumerator-list , }
enum identifier


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.


3. Re: Problemas com enum em C [RESOLVIDO]

Diego Mendes Rodrigues
diegomrodrigues

(usa Ubuntu)

Enviado em 19/06/2018 - 09:30h

Opa!
Em Linguagem C você faz dessa forma:
#include <stdio.h>
#include <string.h>

typedef enum {male, female, gay, flowing_gender} Gender;

struct __person{
char complete_name[256];
char cpf[12], rg[10];
Gender gender;
} person;

int main(void){

strncat(person.complete_name, "Cleinivaldo Sakrudi", 256);
strncat(person.cpf, "82834635005", 12);
strncat(person.rg, "412125304", 10);

person.gender=flowing_gender;

return 0;
}

Abraço,
Diego M. Rodrigues


4. Re: Problemas com enum em C [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 19/06/2018 - 18:48h

Nem sei pra quem dou a melhor resposta :p

Obrigado aos dois por ter respondido :)


5. Re: Problemas com enum em C [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 19/06/2018 - 18:49h

diegomrodrigues escreveu:

Opa!
Em Linguagem C você faz dessa forma:
#include <stdio.h>
#include <string.h>

typedef enum {male, female, gay, flowing_gender} Gender;

struct __person{
char complete_name[256];
char cpf[12], rg[10];
Gender gender;
} person;

int main(void){

strncat(person.complete_name, "Cleinivaldo Sakrudi", 256);
strncat(person.cpf, "82834635005", 12);
strncat(person.rg, "412125304", 10);

person.gender=flowing_gender;

return 0;
}

Abraço,
Diego M. Rodrigues


Qual a diferença entre eu fazer isso:
typedef enum __Gender{male, female, gay, flowing_gender}Gender; 

Do que isso:
typedef enum {male, female, gay, flowing_gender}Gender; 


A mesma coisa com struct:

Qual a diferença entre eu fazer isso:

typedef struct{

double __fock_my_life;
char mongoood[42];

}My_struct;


Do que isso:

typedef struct __My_struct{

double __fock_my_life;
char mongoood[42];

}My_struct;



6. Re: Problemas com enum em C [RESOLVIDO]

Enzo de Brito Ferber
EnzoFerber

(usa FreeBSD)

Enviado em 19/06/2018 - 19:07h


typedef enum { ... } Gender; // (1)
typedef enum __Gender { ... } Gender; // (2)


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:


typedef struct {
int info;
Node *next;
Node *prev;
} Node;


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:


typedef struct __node {
int info;
struct __node *next;
struct __node *prev;
} Node;


Dessa vez você ainda define um nome de tipo, mas tem mecanismo para referenciar a estrutura sendo analisada (pelo parser). Também pode fazer:


typedef struct __node Node;
struct __node {
int info;
Node *next;
Node *prev;
};


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.



7. Re: Problemas com enum em C [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 19/06/2018 - 19:47h

EnzoFerber escreveu:


typedef enum { ... } Gender; // (1)
typedef enum __Gender { ... } Gender; // (2)


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]

Enzo de Brito Ferber
EnzoFerber

(usa FreeBSD)

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.

Dá uma olhada na Wikipedia: https://en.wikipedia.org/wiki/Struct_(C_programming_language)

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]

Enzo de Brito Ferber
EnzoFerber

(usa FreeBSD)

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.







Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts