gpt4 book ai didi

c - 在 C 语言中,宏是否比全局变量运行得更快?如何在运行之间更改宏?

转载 作者:行者123 更新时间:2023-12-02 05:41:30 24 4
gpt4 key购买 nike

我正在用 C 编写一个程序,其中有几个常量我希望我的所有函数都使用。到目前为止,我已经使用了宏。该程序的简化版本如下所示。

#define CONSTANT 10 //int
int multiplication_by_constant(int a){ return a*CONSTANT;}
int main(){
for(int i = 1; i< 10; i++)
printf("%d\n",multiplication_by_constant(i));
}

现在我想通过使用不同的常量值多次运行程序来对程序进行实验。我想自动执行此操作,而不是每次更改 CONSTANT 时都重新编译。我使用了一个简单的解决方案,将宏更改为全局变量,将原始主函数放入新的“program()”函数中,然后在主文件中运行实验,即

int CONSTANT =  10; //int
int multiplication_by_constant(int a){ return a*CONSTANT;}
void program(){
for(int i = 1; i< 10; i++)
printf("%d\n",multiplication_by_constant(i));
}
int main(){
while(CONSTANT < 100){
program();
}
return 0;
}

我发现这个实现会导致循环性能的大幅下降

for(int i = 1; i< 10; i++)
printf("%d\n",multiplication_by_constant(i));

现在需要比我使用宏时多 50% 的运行时间。这是正常的吗?

任何人都可以建议一种更有效的方法来运行我的实验吗?

PS 在 C++ 中,我会通过定义“类程序”、将 CONSTANT 设置为类成员并将“multiplication_by_constant”设置为成员函数来实现。然后我可以使用类定义轻松地通过“main”运行实验,我想我不会有效率损失......我必须在这个实现中使用 C 这就是为什么我求助于全局变量和功能。

最佳答案

好吧,这是性能差异的潜在来源。对于宏,CONSTANT 的值在编译时 是已知的,因此编译器可以利用该知识并以稍微不同的方式构造机器代码。我对您的代码进行了修改,并使用 gcc -Wa,-aldh 为宏版本和全局变量版本获取了汇编列表1,其中有一个有趣的区别。

首先是宏版本:


3 .globl mul_by_const
5 mul_by_const:
6 .LFB2:
7 0000 55 pushq %rbp
8 .LCFI0:
9 0001 4889E5 movq %rsp, %rbp
10 .LCFI1:
11 0004 897DFC movl %edi, -4(%rbp)
12 0007 8B55FC movl -4(%rbp), %edx
13 000a 89D0 movl %edx, %eax<em><strong>
14 000c C1E002 sall $2, %eax
15 000f 01D0 addl %edx, %eax
16 0011 01C0 addl %eax, %eax</strong></em>
17 0013 C9 leave
18 0014 C3 ret

突出显示的行是函数的核心;该函数不是将 %eax 中的值乘以 10,而是先算术左移 2 位,然后进行加法(有效地乘以 5),然后将结果与自身相加。例如,给定 3i 值:

 3 << 2 == 12
3 + 12 == 15
15 + 15 == 30

如果您更改CONSTANT 的值,编译器将生成不同的机器代码(CONSTANT 值为7 会导致算术移位左移 3 后跟减法,而 19 的值左移 3 后跟 3 加法,等等)。

与全局变量版本比较:


2 .globl CONSTANT
3 .data
4 .align 4
7 CONSTANT:
8 0000 0A000000 .long 10
9 .text
10 .globl mul_by_const
12 mul_by_const:
13 .LFB2:
14 0000 55 pushq %rbp
15 .LCFI0:
16 0001 4889E5 movq %rsp, %rbp
17 .LCFI1:
18 0004 897DFC movl %edi, -4(%rbp)
19 0007 8B050000 movl CONSTANT(%rip), %eax
19 0000<strong><em>
20 000d 0FAF45FC imull -4(%rbp), %eax</em></strong>
21 0011 C9 leave
22 0012 C3 ret

此版本使用 imull 操作码进行乘法运算。由于 CONSTANT 的值在编译时未知,因此编译器无法根据该值进行任何特殊优化。

现在,这就是我的特定平台上的情况;我不知道你使用的是什么编译器或者你运行的是什么操作系统,所以你得到的机器代码很可能与我上面的不同。我只是指出在编译时知道 CONSTANT 允许编译器做一些额外的优化。

编辑

如果您更改宏的值,您必须重新编译。你可以把宏放在头文件中,然后写一个脚本来重新生成头文件并重新编译,就像

#!/bin/bash

let CONSTANT=1
while [ $CONSTANT -lt 20 ]
do
cat > const.h << EOF
#ifndef CONST_H
#define CONST_H
#define CONSTANT $CONSTANT
#endif
EOF
# build and run your test code, assuming profiling is captured
# automatically
gcc -o test test.c
./test
let CONSTANT=CONSTANT+1
done

并且您的 C 代码将 #include const.h 文件:

#include "const.h"
int multiplication_by_constant(int a){ return a*CONSTANT;}
...


<补充>1。平台为SUSE Linux Enterprise Server 10 (x86_64),编译器为gcc 4.1.2

关于c - 在 C 语言中,宏是否比全局变量运行得更快?如何在运行之间更改宏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30403270/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com