c/c++语言开发共享有没有办法在C中使用带常量索引的常量数组作为开关案例标签?

我有一些常量值和数组定义它们的标签和哈希码。 例如,

#define LABEL_A 0 //or const int LABEL_A = 0; #define LABEL_B 1 #define LABEL_C 2 #define LABEL_D 3 const char *VALUE[] = {"LABEL_A", "LABEL_B", "LABEL_C", "LABEL_D"}; const int VALUE_HASH[] = {67490, 67491, 67493, 67459); 

在运行时,这些标签可以按任何顺序排列,需要进行相应的解析。 我正在使用开关盒来达到这个目的。 此代码在编译时生成错误“需要常量表达式。

 function(const char* LabelAtRuntime){ int i = getHashCode(LabelAtRuntime); switch(i){ case VALUE_HASH[LABEL_A]: //line giving compile time error break; default: break; } 

但是,当我提供实际常量时,它是有效的。 这段代码效果很好。

 function(const char* LabelAtRuntime){ int i = getHashCode(LabelAtRuntime); switch(i){ case 67490: //line not giving compile time error break; default: break; } 

我以这种方式使用常量来提供更好的代码语义,可读性和可重用性。 请不要提供基于if-else的解决方案。 在上面的例子中,只有4个标签,但实际上可能有100个。

    在C ++中,这编译:

     #include  #include  constexpr int x[] = { 42, 43 }; int main(int argc, char **argv) { switch(atoi(argv[1])) { case x[0]: puts("forty_two"); break; case x[1]: puts("forty_three"); } return 0; } 

    因此,数组上的constexpr似乎是现代C ++中的解决方案。 (注意:问题最初标记为C ++和C)

    如果你想保留arrays,那么在C中是不可能的。 切换情况需要一个整数常量 ,但是一旦在变量中放入一个整数常量,它就会变成一个运行时实体(即使它被声明为const)。 你可以做的是用一堆直接定义替换内存中的数组,并且可能有一个使用其他宏查找宏的宏(如果你想保留你的代码forms):

     #define LABEL_A 0 #define LABEL_B 1 #define LABEL_C 2 #define LABEL_D 2 #define VALUE_HASH__0 67490 #define VALUE_HASH__2 67491 #define VALUE_HASH__3 67491 #define VALUE_HASH__4 64759 //append what Index expands to to VALUE_HASH__ #define HASH_LOOKUP(Index) MC_cat(VALUE_HASH__,Index) #define MC_cat_(X,Y) X##Y #define MC_cat(X,Y) MC_cat_(X,Y) function(const char* LabelAtRuntime){ int i = getHashCode(LabelAtRuntime); switch(i){ case HASH_LOOKUP(LABEL_A) break; default: break; } 

    错误的原因很简单,C不考虑const int LABEL_A=0; 成为编译时常量。 不幸的是,语言是如何定义的。 它可以通过使用#define LABEL_A 0来解决。

    第三种方法是使用枚举,这可能更好,因为它们可用于将所有数据绑定在一起,并在维护期间提供更多的数据完整性:

     typedef enum { LABEL_A, LABEL_B, LABEL_C, LABEL_D, LABELS_N } label_index_t; typedef void func_t (void); typedef struct { const char* str; int hash; func_t* func; } value_t; ... const value_t VALUE [] = { [LABEL_A] = { .str = "LABEL_A", .hash = 67490, .func = a_func }, [LABEL_B] = { .str = "LABEL_B", .hash = 67491, .func = b_func }, [LABEL_C] = { .str = "LABEL_C", .hash = 67493, .func = c_func }, [LABEL_D] = { .str = "LABEL_D", .hash = 67459, .func = d_func }, }; _Static_assert(sizeof VALUE / sizeof *VALUE == LABELS_N, "Size of VALUE does not match label_t."); ... // instead of switch(n): VALUE[n].func(); 

    切换案例需要在编译时知道值。 在您的数组值的情况下,直到运行时才知道这些值。

    如果您使用的是c ++ 11,则可以使用constexpr强制编译器在编译时评估数组值。 下面的代码工作正常。

     constexpr int VALUE_HASH[] = {67490, 67491, 67493, 67459}; int i = getHashCode(LabelAtRuntime); switch(i) { case VALUE_HASH[LABEL_A]: break; default: break; } 

    我不知道你到底在做什么。 但是当我不得不在C中实现菜单UI时,我这样做了:

     // Typedef for a menu item's logic function (callback): typedef void (*menu_item_cb_t)(void*) // Struct defining a menu item: typedef struct menu_item { const char* label; const int hashValue; const menu_item_cb_t callback; const void* callback_arg; } menu_item_t; // Callback for menu item "Do X": void menu_do_x( void* arg ) { // ... } // Definition of menu item "Do X": const menu_item_t menu_item_x = { "Do X", 12345, &menu_do_x, NULL // Don't need it to do x } // All menu items go into one array: const menu_item_t* MENU[] = { &menu_item_x, ...}; #define MENU_ITEM_CNT xxx 

    然后你可以对所选项目采取行动,如:

     void menuItemSelected( const char* label ) { const int hash = getHashCode(label); for ( int i = 0; i < MENU_ITEM_CNT; i++ ) { const menu_item_t* const mi = MENU[i]; if ( hash == mi->hash ) { mi->callback( mi->callback_arg ); break; } } } 

    这种方法当然可以改变,但我希望你能得到这个想法。 它基本上只用于定义具有特定属性的项目(“标签”,“哈希”等等),并直接将它们与实现此项目的相应操作的函数相关联。

    如果VALUE_HASH仅用于获取开关常量,为什么不用跳转表替换它?

    注意,以下都没有经过测试甚至编译。 可能存在语法错误。

    首先为表中的fucntions定义一个类型:

     typedef void (*Callback)(/* parameters you need */); 

    那你需要你的实际function

     void labelAProcessing(/* the parameters as per the typedef */) { /// processing for label A } // etc 

    那你的桌子

     Callback valueCallbacks[] = { labelAProcessing, labelBProcessing, ... }; 

    你的代码就变成了

     int i = getHashCode(LabelAtRuntime); valueCallbacks[i](/* arguments */); 

    我不能过分强调i需要进行validation以确保它是valueCallbacks数组的有效索引,否则,您可能会调用一个随机数,就好像它是一个函数一样。

    操作数是常量是不够的。 在编译时它们是不够的(无论tbat意味着什么,C标准都没有在这些术语中说话)。 案例标签必须是整数常量表达式

    整数常量表达式由C标准严格定义。 粗略地说,整数常量表达式必须由整数常量(也是枚举器,字符常量等)构建,并且不能包含数组或指针,即使它们是常量也是如此。 有关可访问但最详尽的解释,请参阅此示例。

    需要了解更多c/c++开发分享有没有办法在C中使用带常量索引的常量数组作为开关案例标签?,也可以关注C/ C++技术分享栏目—计算机技术网(www.ctvol.com)!

      以上就是c/c++开发分享有没有办法在C中使用带常量索引的常量数组作为开关案例标签?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。

      本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

      ctvol管理联系方式QQ:251552304

      本文章地址:https://www.ctvol.com/c-cdevelopment/978878.html

      (0)
      上一篇 2021年12月12日
      下一篇 2021年12月12日

      精彩推荐