Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在哪里为最有效的代码定义一次常量?_C++_Performance - Fatal编程技术网

C++ 在哪里为最有效的代码定义一次常量?

C++ 在哪里为最有效的代码定义一次常量?,c++,performance,C++,Performance,哪种变体最有效,为什么?或者它们会被优化为相同的代码 char inplace(int i) { // [some check if 0<=i<=2 here] return "azS"[i]; } char infunc(int i) { const char s[] = "azS"; // [some check if 0<=i<sizeof(s)/sizeof(s[0])-1 here] return s[i]; } co

哪种变体最有效,为什么?或者它们会被优化为相同的代码

char inplace(int i) {
    // [some check if 0<=i<=2 here]
    return "azS"[i];
}

char infunc(int i) {
    const char s[] = "azS";
    // [some check if 0<=i<sizeof(s)/sizeof(s[0])-1 here]
    return s[i];
}

const char s[] = "azS";
char inglobals(int i) {
    // [some check if 0<=i<sizeof(s)/sizeof(s[0])-1 here]
    return s[i];
}
charinplace(inti){

//[如果0进行一些检查,我认为编译器会为1和3生成相同的结果,也可能为2生成相同的结果(这取决于它是否意识到可以不将数据复制到堆栈上)。我还假设这不在某个头或类中,这会产生很大的不同(我知道你的代码看起来不像,但我只是小心而已)

一般来说,除非优化证明不是这样,否则我会尽量减少声明的范围(排除3)。在1到2之间,如果更改字符串的内容,1的出错几率要高得多


这让我想到,它很可能对生成的代码没有影响,但选项2比其他2好得多。

我刚刚编译并反汇编了您的代码。
inplace
ingglobals
是相同的。这非常直观:编译器可以将常量字符串存储在
.rodata

奇怪的是,gcc为
infunc
(见下文)生成了相当多的代码,可能是因为您“坚持”在堆栈上有
s
。将
s
定义为
static
会使
infunc
生成与
inplace
inglobals
相同的代码

0000000000000010 : 10: 48 83 ec 18 sub $0x18,%rsp 14: 48 63 ff movslq %edi,%rdi 17: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 1e: 00 00 20: 48 89 44 24 08 mov %rax,0x8(%rsp) 25: 31 c0 xor %eax,%eax 27: c7 04 24 61 7a 53 00 movl $0x537a61,(%rsp) 2e: 0f b6 04 3c movzbl (%rsp,%rdi,1),%eax 32: 48 8b 54 24 08 mov 0x8(%rsp),%rdx 37: 64 48 33 14 25 28 00 xor %fs:0x28,%rdx 3e: 00 00 40: 75 05 jne 47 42: 48 83 c4 18 add $0x18,%rsp 46: c3 retq 47: e8 00 00 00 00 callq 4c 因此,在本例中,GCC选择将字符串与代码内联存储,并在执行期间将其复制到堆栈上。我认为这是非常有效的,因为处理器的缓存中已经填充了字符串,因此不会发生内存访问

编辑


总而言之,这三个版本都是等效的。然而,根据您的编译器实现,一个版本可能比另一个版本更有效。对于GCC,
infunc
似乎对短字符串更有效,因为字符串是随指令一起提取的。对于较大的字符串,我将使用
inplace
inglobals

出生的C++程序员应该学会阅读汇编,这样她就可以尝试并看到差异(如果有的话!)对于她自己!…那么
返回'a'+i
呢?我不想把它作为一个答案,因为我不确定,但我希望在优化过程中,不断的折叠会在相当早的时候将后两者转换为第一个。@akavel:没有“为什么”第三部分。该语言不强制要求其实现的细节。所有三段代码的行为都相同(第三种情况下的全局代码除外),因此它们都可以在任何(可能相同的)语言中实现是的,我知道对于任何3个字符,我们仍然可以很容易地找到一个系列-我可以保持现在的状态,不进一步更改为100个字符(以避免任何多项式答案的机会)?;对于汇编,它不会回答“为什么?”part.argh,我习惯了英特尔语法,从来没有花足够的时间学习AT&T:/案例2(infunc)对于小字符串是否会更快?可能现在需要进行基准测试…如果是,那么案例1(inplace)为什么不进行测试还要优化堆栈吗?非常感谢您的回答和所有这些努力!事实上,为了确保
infunc
更快,需要进行基准测试。我想这不是小事:它的优势只会在字符串不在缓存中的情况下显现出来,也就是说,您必须在每次调用之前刷新缓存,但不能在缓存中测量刷新你的基准。至于
inplace
,你没有告诉编译器创建一个局部变量。我认为这会违反“精神”让编译器做一些它没有被要求做的事情。嗯,很有趣;我没有考虑关于字符串内容变化的含义。因此,我现在也开始怀疑inplace字符串(案例1)根据定义,它实际上是
const
,或者不是。不过,看看user1202136的答案,IIUC gcc认为至少在这种情况下它是
const
。 0000000000000010 : 10: 48 83 ec 18 sub $0x18,%rsp 14: 48 63 ff movslq %edi,%rdi 17: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 1e: 00 00 20: 48 89 44 24 08 mov %rax,0x8(%rsp) 25: 31 c0 xor %eax,%eax 27: c7 04 24 61 7a 53 00 movl $0x537a61,(%rsp) 2e: 0f b6 04 3c movzbl (%rsp,%rdi,1),%eax 32: 48 8b 54 24 08 mov 0x8(%rsp),%rdx 37: 64 48 33 14 25 28 00 xor %fs:0x28,%rdx 3e: 00 00 40: 75 05 jne 47 42: 48 83 c4 18 add $0x18,%rsp 46: c3 retq 47: e8 00 00 00 00 callq 4c