(为了进行搜索或给出合适的标题,我不知道正确的术语)
我一直想知道:如果使用函数调用将参数提供给另一个函数,它是否重要(快速或大小编译)?我可以看到不这样做有助于代码可读性,但有时使用一堆局部变量会变得乏味。
我的意思是:假设这些被多次调用(如在for..loop
中),这之间有任何实际区别:
byte patternType = mCols[i].getPatternType();
byte stepIndex = mCols[i].update(m);
byte patternValue = getPatternValue(patternType, stepIndex);
和此:
byte patternValue = getPatternValue(mCols[i].getPatternType(), mCols[i].update(m));
答案 0 :(得分:3)
评估参数的顺序未定义。如果功能是纯粹的,这应该无关紧要,但如果它们有副作用,它可以。
答案 1 :(得分:0)
这并不重要。如果在启用优化的情况下进行编译,则编译器应在两种情况下都发出相同的代码;但前者的优势在于,在关闭优化的情况下调试更容易。
我刚刚在我的覆盆子pi上试过这个,因为我手头没有arduino。
这是我的y1.c:
#include <stdlib.h>
#include <stdio.h>
typedef signed char byte;
struct something {
byte (*getPatternType)();
byte (*update)(int i);
};
int main(void) {
struct something mCols[20];
int i;
int m=3;
for (i=0; i<20; i++) {
byte patternType=mCols[i].getPatternType();
byte stepIndex=mCols[i].update(m);
byte patternValue=getPatternValue(patternType, stepIndex);
printf("%d\n", patternValue);
}
exit(0);
}
这是y2.c:
#include <stdlib.h>
#include <stdio.h>
typedef signed char byte;
struct something {
byte (*getPatternType)();
byte (*update)(int i);
};
int main(void) {
struct something mCols[20];
int i;
int m=3;
for (i=0; i<20; i++) {
byte patternValue=getPatternValue(mCols[i].getPatternType(), mCols[i].update(m));
printf("%d\n", patternValue);
}
exit(0);
}
然后:
pi@pi$ cc -O4 -S y1.c
pi@pi$ cc -O4 -S y2.c
pi@pi$ diff y1.s y2.s
13c13
< .file "y1.c"
---
> .file "y2.c"
如您所见,在汇编程序级别上,唯一的区别是嵌入式源文件名。
我添加了一个printf,因此编译器不会优化所有内容。它没有,这是y1.s:
.arch armv6
.eabi_attribute 27, 3
.eabi_attribute 28, 1
.fpu vfp
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 2
.eabi_attribute 18, 4
.file "y1.c"
.section .text.startup,"ax",%progbits
.align 2
.global main
.type main, %function
main:
@ args = 0, pretend = 0, frame = 160
@ frame_needed = 0, uses_anonymous_args = 0
stmfd sp!, {r4, r5, r6, lr}
mov r4, #0
sub sp, sp, #160
.L2:
add r5, sp, #0
ldr r3, [r5, r4]!
blx r3
add r4, r4, #8
ldr r3, [r5, #4]
mov r6, r0
mov r0, #3
blx r3
mov r1, r0
mov r0, r6
bl getPatternValue
sxtb r1, r0
ldr r0, .L5
bl printf
cmp r4, #160
bne .L2
mov r0, #0
bl exit
.L6:
.align 2
.L5:
.word .LC0
.size main, .-main
.section .rodata.str1.4,"aMS",%progbits,1
.align 2
.LC0:
.ascii "%d\012\000"
.ident "GCC: (Debian 4.6.3-14+rpi1) 4.6.3"
.section .note.GNU-stack,"",%progbits
注意编译器如何处理循环:控制寄存器r4增加结构(8)的大小而不是1,并在结尾处与160而不是20进行比较。这样可以节省数组索引通常需要的乘法,但是调试器无法在循环中获得i的“实际”值。
答案 2 :(得分:0)
一般建议:
专注于代码清晰度和可读性,让编译器完成其工作并优化掉不必要的东西。不要试图超越你的编译器,它会比程序员在代码优化方面做得更好。
另外,请注意pat建议的评估顺序和序列点。如果你把代码写得足够清楚,那么你通常不需要担心这些事情。