J'essaye de créer une macro de recherche. L'utilisation de l'opérateur ternaire semble être une manière très concise de procéder. Voici ce que j'ai jusqu'à présent:

#define SQL_LOOKUP_TABLE(x) (strncmp(x, "int", strlen(x)) == 0) ? "INTEGER" : SQL_LOOKUP_TABLE1(x)
#define SQL_LOOKUP_TABLE1(x) (strncmp(x, "char", strlen(x)) == 0) ? "TEXT" : SQL_LOOKUP_TABLE2(x)
#define SQL_LOOKUP_TABLE2(x) (strncmp(x, "double", strlen(x)) == 0) ? "REAL" : ""

Je veux passer le type sous forme de chaîne en c, puis récupérer le type SQL correspondant sous forme de chaîne. Cela fonctionne très bien quand je fais quelque chose comme ça:

printf("Ternary test: %s\n", SQL_LOOKUP_TABLE("double")); //output "REAL"

Ce que je veux vraiment faire, c'est prendre ces informations et créer une instruction SQL CRUD entière. Le problème survient lorsque j'essaie de créer la chaîne à l'intérieur d'une autre macro. Quelque chose comme ça ne fonctionne pas:

#define BUILD_A_STRING(x) "CREATE TABLE ( " SQL_LOOKUP_TABLE( x ) 

Je reçois une erreur:

error C2064: term does not evaluate to a function taking 337 arguments

Remarque rapide, cela fonctionne (renvoie "REAL"):

#define BUILD_A_STRING(x) SQL_LOOKUP_TABLE( x ) 

Des idées pourquoi je ne peux pas appeler la macro à l'intérieur d'une autre macro et également créer une chaîne?

Edit (au risque de fournir TMI): C'est ce que je veux vraiment faire:

typedef struct {
    double yomama;
    int x;
    char shiboopy[100];
} test_data1;

#define EXPAND_AS_CREATE_STATEMENT(type, element, struct_name) SQL_LOOKUP_TABLE( #type) " " # element ", "
#define test_data1_TABLE(ENTRY)     \
    ENTRY(double, yomama, test_data1)           \
    ENTRY(int, x, test_data1)   \
    ENTRY(char, shiboopy, test_data1)
char* create_stmt = "CREATE TABLE test_data1 (" test_data1_TABLE(EXPAND_AS_CREATE_STATEMENT) ");";  \

En gros, utilisez une macro X pour définir les types de données d'une structure, puis développez-la en toutes les instructions CRUD dont je pourrais avoir besoin.

0
Galactasm 27 juil. 2017 à 23:14

2 réponses

La concaténation de chaîne lexicale est une opération de préprocesseur. L'opérateur ternaire est une opération d'exécution. Lorsque les chaînes sont tentées d'être concaténées, le préprocesseur recherchera les littéraux de chaîne adjacents, mais n'en trouvera pas car

"CREATE TABLE ( " SQL_LOOKUP_TABLE( x )

Est prétraité pour

"CREATE TABLE ( " (strncmp(x, "int", strlen(x)) == 0) ? "INTEGER" : SQL_LOOKUP_TABLE1(x)

Et le préprocesseur ne connaît pas strncmp, strlen ou l'opérateur ternaire.

Pour faire ce que vous voulez, vous devez faire les choses conditionnelles lorsque le préprocesseur s'exécute. Le préprocesseur C est trop simpliste pour cela, cependant, il nécessiterait un préprocesseur plus sophistiqué comme m4 pour cela.
L'autre façon défavorable serait de faire la concaténation au moment de l'exécution avec un peu de surcharge, évidemment.

Je vous recommande de repenser votre conception. Une table de hachage peut être utile: elle fonctionnera et elle est plus propre et plus efficace.

2
cadaniluk 27 juil. 2017 à 20:34

La réponse de @Downvoter explique la raison de l'erreur que vous obtenez. Je pense qu'il vaut mieux utiliser une fonction dans votre cas. quelque chose comme:

char* build_str(char* type)
{
    static char str[80];
    char* sql_type_str = SQL_LOOKUP_TABLE(type);
    strcat(str, "CREATE TABLE (");
    strcat(str,sql_type_str);
    /* strcat others params */
    return str;
 }

Vous devrez peut-être donner plus de détails sur la manière dont vous prévoyez d’utiliser BUILD_STRING.

0
Mouin 27 juil. 2017 à 22:18