我有几个函数中定义的常量数组 lot 。如下所示:
const float values[4] = {-4312.435f, -432.44333f, 4.798, 7898.89};
在检查gcc汇编程序输出后,我注意到这些常量是在每次运行函数时生成的。那是非常低效的。我怀疑这是因为C / C ++规范说即使数据是const
,编译器也不能假设它不会被修改(例如通过const_cast)。是否有可能强制gcc不这么认为?
我想在函数体内定义这些常量,因为它们非常复杂。将常数保持在他们使用的位置附近有助于可维护性。
修改
不幸的是,即使定义常量static
,它们也会在每次运行时重新生成。如果有帮助,我会使用-O3。
EDIT2
好的,对于第一次编辑感到抱歉,我需要进一步调查。似乎特定的设置以前在某种程度上不允许gcc初始化常量而不重新生成它们。
EDIT3
问题出在我的测试用例中,我在附近定义了两个数组,但其中一个数组是为了生成的。然后汇编程序误导了我。再次抱歉&谢谢!
答案 0 :(得分:12)
使用static
关键字声明它们。
编辑:回复您的评论,以便我向您展示一些代码:
这是预期的行为。你在做什么或看到不同的东西?
$ cat foo.c++
int main(void)
{
static const float foos[] = {1.234f, 5.678f, 9.012f};
return 0;
}
$ g++ -S foo.c++
$ cat foo.s
.file "foo.c++"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl $0, %eax
leave
ret
.cfi_endproc
.LFE0:
.size main, .-main
.section .rodata
.align 4
.type _ZZ4mainE4foos, @object
.size _ZZ4mainE4foos, 12
_ZZ4mainE4foos:
.long 1067316150
.long 1085649453
.long 1091580199
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
.section .note.GNU-stack,"",@progbits
答案 1 :(得分:11)
编译器实际上可以假定定义为const
的值永远不会改变。 (通过const
变量访问的内容是另一个故事;我只讨论定义可见且具有const
的情况。)这里得到的问题是标准说如果你递归调用你的函数,values
的地址每次都会不同。
因此,使用语言功能意味着每次调用函数时声明都引用相同的内容。也就是说,static
函数变量:
static const float values[4] = {-4312.435f, -432.44333f, 4.798, 7898.89};
答案 2 :(得分:5)
将定义更改为
static const float values[4] = {-4312.435f, -432.44333f, 4.798, 7898.89};
静态数组不会放在函数堆栈中,因此不会为每个函数调用重新生成它们。
你也可以尝试将这个数组从函数移到外面(使它成为一个带有function1_values
之类前缀的全局数组。
编辑:
如果您将"flds"
或"movss"
指令视为重新生成 - 则不是。常量将存储在elf文件的.rodata
部分中,但要使用它们,编译器必须将它们加载到寄存器中。所以fld
& movss
只会从内存加载常量,如果不加载它就无法从内存中获取值。
示例代码:
int function4(float *a, int sz)
{
int i;
const float values[4] = {-4312.435f, -432.44333f, 4.798, 7898.89};
for(i=4;i<sz;i++);
a[i]+=a[i-1]*values[0]+a[i-2]*values[1]+a[i-3]*values[2]+a[i-4]*values[3];
return i;
}
gcc-4.5.2 -O3 a.c -fverbose-asm -mfpmath = sse -march = native -S
用于循环体的Assembelr:
.L2:
movl -20(%ebp), %ecx # %sfp, D.2677
leal (%edx,%ecx), %ecx #, D.2677
movss .LC0, %xmm0 #, tmp192 << THIS is a constant loading
mulss (%edx,%edi), %xmm0 #* prephitmp.46, tmp192
movss .LC1, %xmm1 #, tmp179
mulss (%edx,%esi), %xmm1 #* prephitmp.46, tmp179
addss %xmm1, %xmm0 # tmp179, tmp192
movss .LC2, %xmm1 #, tmp183
mulss (%edx,%ebx), %xmm1 #* prephitmp.46, tmp183
addss %xmm1, %xmm0 # tmp183, tmp192
movss .LC3, %xmm1 #, tmp187
movl -16(%ebp), %ebx # %sfp,
常量存储在.rodata
:
.section .rodata.cst4,"aM",@progbits,4
.align 4
.LC0:
.long -981023877
.align 4
.LC1:
.long -1009239873
.align 4
.LC2:
.long 1083803959
.align 4
.LC3:
.long 1173804831
答案 3 :(得分:1)
放置所有
const float values[4] = {-4312.435f, -432.44333f, 4.798, 7898.89};
在单独的.cpp文件中。
在使用这些数组的文件中将它们声明为extern
extern const float values[4];
尽管如评论中所述,对此进行了概述(在真实的应用程序中,这些数组可能会从l1 / l2缓存中抛出)。出于非直观原因,这可能会降低性能。
答案 4 :(得分:0)
我不明白你在哪里看到问题,编译器做了一个合理的事情来优化掉常量。您可以通过要求外部链接来防止这种情况:
extern const float values[4];