【问题标题】:Macro Expansion Ternary Lookup Table宏扩展三元查找表
【发布时间】:2018-01-03 17:46:57
【问题描述】:

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

#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 语句。

【问题讨论】:

  • 你如何尝试使用BUILD_A_STRING
  • 您的编译器应该有一个仅预处理选项,允许您查看扩展。试试看.....而且,为什么不直接创建一个函数呢?使用宏,你可能会得到大量重复的代码,可能会使 exe 膨胀。
  • not evaluate to a function taking 337 arguments 告诉我你设法以某种方式松开了右括号。

标签: c macros c-preprocessor


【解决方案1】:

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

"CREATE TABLE ( " SQL_LOOKUP_TABLE( x )

被预处理为

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

而预处理器不知道strncmpstrlen 或三元运算符。

要做你想做的事,你必须在预处理器运行时做一些有条件的事情。 C 预处理器太简单了,不过,它需要一个更复杂的预处理器,比如 m4。
显然,另一种不利的方法是在运行时进行连接,但会产生一些开销。

我建议您重新考虑您的设计。哈希表可能会派上用场:它可以工作,而且更清洁、更高效。

【讨论】:

    【解决方案2】:

    @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

    【讨论】:

      【解决方案3】:

      我正在解释这个:

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

      ...还有这个:

      这才是我真正想做的:

      ...覆盖这个:

      我想在c中将类型作为字符串传入,然后将对应的SQL类型作为字符串取回。

      我认为您不应该将类型作为 C 字符串 传递;这对您没有任何好处,因为您对该字符串所做的只是将其直接传递回宏(而宏对字符串无能为力)。如果您将 token 传递给宏,则可以让 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"
      

      token 传递给这个宏,而不是 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 宏添加分隔符宏支持)。

      【讨论】:

      • 传递令牌,而不是字符串化令牌与我的 X 宏完美配合!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-02
      • 2019-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-05
      • 2012-08-01
      相关资源
      最近更新 更多