Existe a possibilidade de converter nomes de enumeradores em string em C?
Uma maneira, fazer o pré-processador fazer o trabalho. Ele também garante que seus enums e strings estejam sincronizados.
#define FOREACH_FRUIT(FRUIT) \
FRUIT(apple) \
FRUIT(orange) \
FRUIT(grape) \
FRUIT(banana) \
#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,
enum FRUIT_ENUM {
FOREACH_FRUIT(GENERATE_ENUM)
};
static const char *FRUIT_STRING[] = {
FOREACH_FRUIT(GENERATE_STRING)
};
Depois que o pré-processador estiver pronto, você terá:
enum FRUIT_ENUM {
apple, orange, grape, banana,
};
static const char *FRUIT_STRING[] = {
"apple", "orange", "grape", "banana",
};
Então você poderia fazer algo como:
printf("enum apple as a string: %s\n",FRUIT_STRING[apple]);
Se o caso de uso for literalmente apenas imprimir o nome enum, adicione as seguintes macros:
#define str(x) #x
#define xstr(x) str(x)
Então faça:
printf("enum apple as a string: %s\n", xstr(apple));
Nesse caso, pode parecer que a macro de dois níveis é supérflua, no entanto, devido ao modo como a estringificação funciona em C, ela é necessária em alguns casos. Por exemplo, digamos que queremos usar um #define com um enum:
#define foo apple
int main() {
printf("%s\n", str(foo));
printf("%s\n", xstr(foo));
}
O resultado seria:
foo
apple
Isso ocorre porque str irá restringir a entrada foo em vez de expandi-la para ser apple. Usando xstr, a expansão da macro é feita primeiro e, em seguida, o resultado é codificado.
Consulte Stringificação para obter mais informações.
#define GENERATE_ENUM(ENUM) PREFIX##ENUM,
Em uma situação em que você tem:
Gosto de colocar isso no arquivo de cabeçalho onde o enum é definido:
fonte
enumToString(apple)
do que digitar"apple"
? Não é como se houvesse qualquer tipo de segurança em qualquer lugar. A menos que eu esteja perdendo algo, o que você sugere aqui é inútil e apenas consegue ofuscar o código.Não existe uma maneira simples de fazer isso diretamente. Mas o P99 tem macros que permitem criar esse tipo de função automaticamente:
em um arquivo de cabeçalho, e
em uma unidade de compilação (arquivo .c) deve, então, fazer o truque, nesse exemplo a função seria chamada
color_getname
.fonte
Eu encontrei um truque do pré-processador C que está fazendo o mesmo trabalho sem declarar uma string de array dedicada (Fonte: http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/c_preprocessor_applications_en ).
Enums sequenciais
Seguindo a invenção de Stefan Ram, enums sequenciais (sem declarar explicitamente o índice, por exemplo
enum {foo=-1, foo1 = 1}
) podem ser realizados como este truque genial:Isso dá o seguinte resultado:
Enums não sequenciais
Como eu queria mapear as definições dos códigos de erro para strings de array, para que eu pudesse anexar a definição de erro bruta ao código de erro (por exemplo
"The error is 3 (LC_FT_DEVICE_NOT_OPENED)."
), estendi o código de forma que você possa determinar facilmente o índice necessário para os respectivos valores enum :Neste exemplo, o pré-processador C gerará o seguinte código :
Isso resulta nos seguintes recursos de implementação:
fonte
Você não precisa depender do pré-processador para garantir que seus enums e strings estejam sincronizados. Para mim, o uso de macros torna o código mais difícil de ler.
Usando Enum e uma série de strings
Nota: as strings na
fruit_str
matriz não precisam ser declaradas na mesma ordem que os itens enum.Como usá-lo
Adicionando uma verificação de tempo de compilação
Se você tem medo de esquecer uma string, pode adicionar a seguinte verificação:
Um erro seria relatado em tempo de compilação se a quantidade de itens enum não corresponder à quantidade de strings na matriz.
fonte
Uma função como essa sem validar o enum é um pouco perigosa. Eu sugiro usar uma instrução switch. Outra vantagem é que isso pode ser usado para enums que possuem valores definidos, por exemplo, para sinalizadores onde os valores são 1,2,4,8,16 etc.
Além disso, coloque todas as strings de enum juntas em uma matriz: -
definir os índices em um arquivo de cabeçalho: -
Isso facilita a produção de diferentes versões, por exemplo, se você deseja fazer versões internacionais de seu programa com outros idiomas.
Usando uma macro, também no arquivo de cabeçalho: -
Faça uma função com uma instrução switch, isso deve retornar um
const char *
porque as strings consts estáticas: -Se estiver programando com Windows, os valores ID_ podem ser valores de recursos.
(Se estiver usando C ++, todas as funções podem ter o mesmo nome.
)
fonte
Uma alternativa mais simples para a resposta de "enums não sequenciais" de Hokyo, com base no uso de designadores para instanciar a matriz de string:
fonte
Eu normalmente faço isso:
fonte