如何在编译时使用常量参数进行gcc优化函数调用?

如何在编译时使用常量参数进行gcc优化函数调用?,c,gcc,C,Gcc,我试图解析用户输入,并根据用户给出的命令执行一些任务。因为在C语言中,switch不能处理字符串,所以我决定使用字符串哈希值的switch来比较要执行的命令 现在,在下面的内容中维护所有可用命令的所有哈希列表 #define EXIT 6385204799 ... switch(hash(command)){ case hash("exit"): exit(); // I know, case labels must be compile time constants

我试图解析用户输入,并根据用户给出的命令执行一些任务。因为在C语言中,switch不能处理字符串,所以我决定使用字符串哈希值的switch来比较要执行的命令

现在,在下面的内容中维护所有可用命令的所有哈希列表

#define EXIT 6385204799
...
switch(hash(command)){
    case hash("exit"): exit();
    // I know, case labels must be compile time constants
    // but that should be fulfilled in my case
}
这是一项非常乏味的任务,我想知道是否有办法说服
gcc
在编译时使用常量参数来计算哈希函数,这样我就可以使用类似的方法了

#define EXIT 6385204799
...
switch(hash(command)){
    case hash("exit"): exit();
    // I know, case labels must be compile time constants
    // but that should be fulfilled in my case
}
我知道我可以使用例如元编程,但我对gcc的解决方案更感兴趣

有可能吗

#include <stdio.h>


unsigned long hash(const char *str)
{
        unsigned long hash = 5381;
        int c;

        while ((c = *str++))
                hash = ((hash << 5) + hash) + c;
        return hash;
}

int main( int argc, char **argv ) {
        char *command=NULL;
        size_t size=0;
        printf("Enter string:");
        getline(&command, &size, stdin);
        printf("%ld",hash("exit")); // I want this to evaluate in compile time
        printf("%ld",hash(command)); // and this not
        return 0;
}
#包括
无符号长哈希(const char*str)
{
无符号长散列=5381;
INTC;
而((c=*str++)

hash=((hash您可以构建一个C程序,该程序将依赖于您的
hash
函数,并根据配置文件生成头定义文件

配置文件:
EXIT“EXIT”
->流程配置文件->头文件(commands.h):
#定义退出6385204799

然后,您可以在您的程序中包含
commands.h
,并在switch语句中使用enum

switch(hash(command)){
    case EXIT: exit();
有可能吗

#include <stdio.h>


unsigned long hash(const char *str)
{
        unsigned long hash = 5381;
        int c;

        while ((c = *str++))
                hash = ((hash << 5) + hash) + c;
        return hash;
}

int main( int argc, char **argv ) {
        char *command=NULL;
        size_t size=0;
        printf("Enter string:");
        getline(&command, &size, stdin);
        printf("%ld",hash("exit")); // I want this to evaluate in compile time
        printf("%ld",hash(command)); // and this not
        return 0;
}

GCC不能(对于C,它可以为C++,见下文),但CLAN/LLVM(版本3.9-1)可以使用.<代码> -O2< /Cord>开关使能优化2(或更高)。 。请参阅反汇编-没有对哈希函数的调用,没有循环;编译器已在编译时计算哈希。此简化形式的测试用例:

#include <stdio.h>

static unsigned long hash(const char *str)
{
        unsigned long hash = 5381;
        int c;

        while ((c = *str++))
                hash = ((hash << 5) + hash) + c;
        return hash;
}

int main( int argc, char **argv ) {
        size_t size=0;
        printf("%ld",hash("exit")); // I want this to evaluate in compile time
        return 0;
}

这是C++ 14代码,你需要使用<代码> -STD= C++ 14 <代码>编译它(或者使用GCC 6 +,这是默认的)。(当然,代码不是习惯的C++——它的目的是尽可能地接近前面的例子)。

最简单的方法: 如果4个字符足够,您可以使用诸如“exit”/“tixe”(取决于endianness)之类的文字来代替哈希函数。请注意单引号

任何使其成为常量表达式的方法都将依赖于编译器,因此您可以使用允许宏返回值的方法。它看起来像
({int hash=5381;/*do stuff*/hash;})
…但您可能需要
#pragma GCC push_选项
#pragma GCC优化(“展开循环”)
在您的案例陈述之前和
#pragma GCC pop_选项之后

另一种方法是将字符串映射到枚举,并使用按字母排序的字符串的二进制搜索而不是哈希。您可以使用X宏来简化添加和删除命令。在本例中,我也将其用于函数原型和case语句(不需要,只是对于一个简单的示例更易于使用)

#包括
#定义MYXMACRO(OP)\
OP(酒吧)\
OP(出口)\
OP(foo)
#定义为_ENUM(x,…)MYENUM_35;##x,
枚举{MYXMACRO(AS_enum)MYENUMCOUNT};
#未定义为_ENUM
#定义为_字符串(x,…)#x,
const char*mystrings[]={MYXMACRO(AS_STRING)};
#未定义为_字符串
#定义为(x,…)void do###x(void);
MYXMACRO(AS_原型)
void do_默认值(void);
#undef AS_原型
int mybsearch(const char*命令){
大小(bot=0,top=MYENUMCOUNT,i=((bot+top)>>1)和(~1);
int-cmp;
对于(;bot1)和(~1)){
cmp=strcmp(命令,mystrings[i]);
如果(!cmp)返回i;//找到匹配项
如果(cmp>0)bot=i+1,则为else;
else-top=i-1;
}
返回-1;
}
void do_命令(const char*命令){
#定义为_CASE(x,…)CASE MYENUM_35;##x:do_35;###x(u VA#u ARGS);break;
开关(mybsearch(命令)){
MYXMACRO(按案例)
默认值:do_default();
}
}
#未定义MYXMACRO

这几乎是不可能的。你想让优化器运行你的非平凡代码并计算结果。它不是这样设计的。@davmac很有趣。我会在桌面上看一次证明…@EugeneSh。我最初的答案是错误的-现在编辑。Clang可以做,但GCC不能。你可以编写一个程序,在中生成哈希值构建系统在C之前运行的标头compilation@M.M:您的建议可能就是OP所指的元编程。非常令人印象深刻的是,编译器将模拟一个循环,它知道该循环具有纯常量输入。