简体   繁体   English

函数调用作为其他函数的参数

[英]Function call as argument to other function

(I didn't know the correct terminology for this in order to do a search or give an appropriate title) (我不知道要搜索或给出适当标题的正确术语)

I have always wondered: does it matter (speedwise or compiled sizewise) if one uses a function call to provide the argument to another function? 我一直想知道:如果使用函数调用为另一个函数提供参数,是否有关系(在速度上还是在大小上进行编译)? I can see how not doing that can aid code readability but sometimes using a bunch of local variables gets tedious. 我可以看到这样做会如何提高代码的可读性,但是有时使用一堆局部变量会变得乏味。

What I mean: assuming these are called many times (as in a for..loop ) is there any practical difference between this: 我的意思是:假设多次调用它们(如for..loop ),这之间有什么实际区别:

      byte patternType = mCols[i].getPatternType();
      byte stepIndex = mCols[i].update(m);
      byte patternValue = getPatternValue(patternType, stepIndex);

and this: 和这个:

      byte patternValue = getPatternValue(mCols[i].getPatternType(), mCols[i].update(m));

The order in which the parameters are evaluated is undefined. 参数的评估顺序是不确定的。 If the functions are pure, this should not matter, but if they have side-effects, it could. 如果函数是纯函数,则无关紧要,但如果它们具有副作用,则可以。

It doesn't really matter. 没关系。 If you compile with optimizations turned on, the compiler should emit the same code in both cases; 如果在启用优化的情况下进行编译,则两种情况下编译器都应发出相同的代码; but the former has the advantage that it's easier to debug with optimizaton turned off. 但前者的优势在于,关闭优化后更容易调试。

I just tried this on my raspberry pi, as i don't have an arduino at hand. 我刚刚在树莓派上尝试了此操作,因为手头没有arduino。

This is my y1.c: 这是我的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);
}

and this is y2.c: 这是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);
}

Then: 然后:

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"

As you see, on assembler level, the only difference is the embedded source file name. 如您所见,在汇编程序级别,唯一的区别是嵌入式源文件名。

I added a printf so the compiler wouldn't just optimize out everything. 我添加了一个printf,这样编译器不仅会优化所有内容。 It didn't, this is y1.s: 没错,这是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

Note how the compiler treats the loop: the controlling register r4 is incremented by the size of the structure (8), not by one, and compared to 160, not 20, at the end. 请注意编译器如何处理循环:控制寄存器r4递增结构(8)的大小,而不是增加1,最后与160而不是20进行比较。 This saves the multiplication that the array index normally needs, but there's no way for a debugger to get the "real" value of i within the loop. 这样可以节省通常需要数组索引的乘法,但是调试器无法在循环内获取i的“实际”值。

General advice: 一般建议:

Focus on code clarity and readability, let compiler does its work and optimizes away unnecessary things. 专注于代码的清晰度和可读性,让编译器完成工作并优化不必要的事情。 Don't try to outsmart your compiler, it will do better than the programmer most of the cases at code optimization. 不要试图使您的编译器胜于智能,在代码优化的大多数情况下,它会比程序员做得更好。

Also, be careful of order of evaluation and sequence points as pat suggested. 另外,请注意评估顺序和建议的顺序点。 You generally don't need to be concerned about these things if you write the code clear enough, tough. 如果您编写的代码足够清晰,清晰易懂,则通常无需担心这些事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM