宏扩展三元查找表

时间:2017-07-27 20:14:08

标签: c macros c-preprocessor

我正在尝试创建一个查找宏。使用三元运算符似乎是一种非常简洁的方法。这就是我到目前为止所拥有的:

#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" : ""

我想在c中将类型作为字符串传递,然后以字符串形式返回相应的SQL类型。当我做这样的事情时它很有用:

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

我真正想要做的是获取此信息并构建整个SQL CRUD语句。当我尝试在另一个宏内部构建字符串时,问题就出现了。这样的事情不起作用:

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

我收到错误:

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

快速注意,这确实有效(返回" REAL"):

#define BUILD_A_STRING(x) SQL_LOOKUP_TABLE( x ) 

为什么我无法在另一个宏内部调用宏并构建字符串?

编辑(存在提供TMI的风险): 这就是我真正想要做的事情:

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) ");";  \

基本上使用X宏来定义结构的数据类型,然后将其扩展为我可能需要的任何CRUD语句。

3 个答案:

答案 0 :(得分:2)

词法字符串连接是一个预处理器操作。三元运算符是运行时操作。当尝试连接字符串时,预处理器将查找相邻的字符串文字,但将无法找到任何字符串,因为

"CREATE TABLE ( " SQL_LOOKUP_TABLE( x )

预处理

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

并且预处理器不了解strncmpstrlen或三元运算符。

要执行您想要的操作,您必须在预处理器运行时执行条件操作。然而,C预处理器过于简单化,需要更复杂的预处理器,如m4。
另一个不利的方法是在运行时进行串联,显然需要一点开销。

我建议你重新考虑你的设计。哈希表可能会派上用场:它会起作用,它更干净,更有效。

答案 1 :(得分:1)

我正在解释这个:

我真正想要做的是获取此信息并构建一个完整的SQL CRUD语句。

......而且这个:

这就是我真正想要做的事情:

......如果压倒一切:

我想在c中将类型作为字符串传递,然后以字符串形式返回相应的SQL类型。

我认为您不应该将该类型作为 C字符串传递;什么都没有得到你,因为你正在使用该字符串正在将它传递回宏(并且宏不能对字符串做任何事情)。如果您将标记传递给宏,则可以让C预处理器本身进行查找。

这就是我的意思:

#define SQL_LOOKUP_TABLE(x) DB_TYPE_FOR_ ## x
#define DB_TYPE_FOR_double  "REAL"
#define DB_TYPE_FOR_int     "INTEGER"
#define DB_TYPE_FOR_char    "TEXT"

令牌传递给此宏,而不是 stringified 令牌:

#define EXPAND_AS_CREATE_STATEMENT(type, element, struct_name) \
     SQL_LOOKUP_TABLE(type) " " # element ", "

......而且这个:

"CREATE TABLE test_data1 (" test_data1_TABLE(EXPAND_AS_CREATE_STATEMENT) ");"

...只是扩展到这个:

"CREATE TABLE test_data (" "REAL" " " "yomama" ", " "INTEGER" " " "x" ", " "TEXT" " " "shaboopy" ", " ");"

...字符串文字串联后等同于:

"CREATE TABLE test_data (REAL yomama, INTEGER x, TEXT shaboopy, );"

没有strcmp,没有三元链,不需要哈希表。现在,我不确定您的数据库引擎是否足够懒,可以接受参数列表中的尾随逗号,但这是另一个问题(最简单的解决方案是为X宏添加分隔符宏支持)。

答案 2 :(得分:0)

@ Downvoter'答案解释了你得到错误的原因。 我觉得在你的情况下使用一个函数会更好。 类似的东西:

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;
 }

也许你必须详细说明你打算如何使用BUILD_STRING