2008-10-12 10 views
43

Par exemple, comment éviter d'écrire le 'nom_fonction' deux fois?Comment faire une chaîne de caractère à partir de la valeur d'une macro C?

#ifndef TEST_FUN 
# define TEST_FUN func_name 
# define TEST_FUN_NAME "func_name" 
#endif 

Je voudrais suivre la règle Single Point of Truth.

Version de préprocesseur C:

$ cpp --version 
cpp (GCC) 4.1.2 20070626 (Red Hat 4.1.2-14) 
+0

double possible de [C macros pour créer des chaînes] (http://stackoverflow.com/questions/798221/c-macros -to-create-strings) – rjstelling

Répondre

67

He who is Shy* vous a donné le germe d'un answer, mais seulement le germe. La technique de base pour convertir une valeur en une chaîne dans le pré-processeur C est en effet par l'intermédiaire de l'opérateur « # », mais un simple translittération de la solution proposée obtient une erreur de compilation:

#define TEST_FUNC test_func 
#define TEST_FUNC_NAME #TEST_FUNC 

#include <stdio.h> 
int main(void) 
{ 
    puts(TEST_FUNC_NAME); 
    return(0); 
} 

L'erreur de syntaxe est en la ligne 'puts()' - le problème est un 'errant #' dans la source.

Dans la section 6.10.3.2 de la norme C, « L'opérateur # », il dit:

Each # preprocessing token in the replacement list for a function-like macro shall be followed by a parameter as the next preprocessing token in the replacement list.

Le problème est que vous pouvez convertir arguments macro en chaînes - mais vous ne pouvez pas convertir au hasard les éléments qui ne sont pas des arguments de macro. Donc, pour obtenir l'effet que vous recherchez, vous devrez certainement faire un peu plus de travail.

#define FUNCTION_NAME(name) #name 
#define TEST_FUNC_NAME FUNCTION_NAME(test_func) 

#include <stdio.h> 

int main(void) 
{ 
    puts(TEST_FUNC_NAME); 
    return(0); 
} 

Je ne suis pas tout à fait clair sur la façon dont vous envisagez d'utiliser les macros, et comment vous prévoyez d'éviter la répétition tout à fait. Cet exemple légèrement plus élaboré pourrait être plus instructif. L'utilisation d'une macro équivalente à STR_VALUE est un idiome nécessaire pour obtenir le résultat souhaité.

#define STR_VALUE(arg)  #arg 
#define FUNCTION_NAME(name) STR_VALUE(name) 

#define TEST_FUNC  test_func 
#define TEST_FUNC_NAME FUNCTION_NAME(TEST_FUNC) 

#include <stdio.h> 

static void TEST_FUNC(void) 
{ 
    printf("In function %s\n", TEST_FUNC_NAME); 
} 

int main(void) 
{ 
    puts(TEST_FUNC_NAME); 
    TEST_FUNC(); 
    return(0); 
} 

* Au moment où cette réponse a été écrit, shoosh « nom utilisé « Timide » dans le cadre du nom.

+0

Cela fonctionne.Je vous remercie. J'ai posté un exemple de travail qui reflète la motivation pour le code. http://stackoverflow.com/questions/195975/how-to-make-a-char-string-from-ac-macros-value#196093 – jfs

+0

Réécriture presque littérale d'un commentaire originalement réalisé 2012-10-12 21:37 (qui affichait un __func__ gras au lieu de __func__) - Bien sûr, dans C99, nous pourrions utiliser l'identificateur prédéfini '__func__' dans la fonction pour désigner le nom de la fonction. Cependant, ce n'est pas une aide en dehors de la fonction, et c'est là que la chaîne de nom de la fonction est vraiment nécessaire. –

+0

votre deuxième code ne fonctionne pas pour moi. Le 'test_func' devrait être une macro pour le cas d'OP, je pense. Si vous mettez #define test_func mon_test_func. (faisant ainsi de test_func une macro), il imprime toujours 'test_func' et non' my_test_func'. –

-2

#define TEST_FUN_NAME #FUNC_NAME

voir here

+2

Cela ne fonctionne pas. Vois ma réponse. – jfs

+2

Ceci est en effet incorrect - voir aussi ma réponse. C'est aussi incroyable qu'il y ait 4 votes. Le problème est, il semble que ce soit plus ou moins correct, si vous ne réfléchissez pas attentivement. –

0
#include <stdio.h> 

#define QUOTEME(x) #x 

#ifndef TEST_FUN 
# define TEST_FUN func_name 
# define TEST_FUN_NAME QUOTEME(TEST_FUN) 
#endif 

int main(void) 
{ 
    puts(TEST_FUN_NAME); 
    return 0; 
} 

Référence: page de Wikipédia C preprocessor

+1

Cela ne marche pas non plus. Vois ma réponse. – jfs

12

@Jonathan Leffler: Merci. Votre solution fonctionne.

Un exemple de travail complet:

/** compile-time dispatch 

    $ gcc -Wall -DTEST_FUN=another_func macro_sub.c -o macro_sub && ./macro_sub 
*/ 
#include <stdio.h> 

#define QUOTE(name) #name 
#define STR(macro) QUOTE(macro) 

#ifndef TEST_FUN 
# define TEST_FUN some_func 
#endif 

#define TEST_FUN_NAME STR(TEST_FUN) 

void some_func(void) 
{ 
    printf("some_func() called\n"); 
} 

void another_func(void) 
{ 
    printf("do something else\n"); 
} 

int main(void) 
{ 
    TEST_FUN(); 
    printf("TEST_FUN_NAME=%s\n", TEST_FUN_NAME); 
    return 0; 
} 

Exemple:

$ gcc -Wall -DTEST_FUN=another_func macro_sub.c -o macro_sub && ./macro_sub 
do something else 
TEST_FUN_NAME=another_func