在我的源代码中,我看到了arm编译器的奇怪行为,它对字符串进行了冗余迭代,这是不必要的。我在这里展示了一个最小的例子来说明这一点,并在下面提出我的问题
#include <string.h>
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
int MAX_FILE_NAME = 2500;
int F(char *file){
int file_len = MIN(strlen(file), MAX_FILE_NAME - 1);
return file_len;
}
int main(void) {
F(__FILE__);
return 0 ;
}
Run Code Online (Sandbox Code Playgroud)
编译为:
arm-none-eabi-gcc -nostdlib -Xlinker -Map="m7_experiments.map" -Xlinker --cref -Xlinker --gc-sections -Xlinker -print-memory-usage -mcpu=cortex-m7 -mfpu=fpv5-sp-d16 -mfloat-abi=hard -mthumb -T "m7_experiments_Debug.ld" -o "m7_experiments.axf" ./src/cr_startup_cm7.o ./src/crp.o ./src/flashconfig.o ./src/m7_experiments.o
Run Code Online (Sandbox Code Playgroud)
导致:
Dump of assembler code for function F:
0x00000104 <+0>: push {r4, lr}
0x00000106 <+2>: mov r4, r0
0x00000108 <+4>: bl 0x13c <strlen>
0x0000010c <+8>: mov r2, r0
0x0000010e <+10>: ldr r3, [pc, #20] ; (0x124 <F+32>)
0x00000110 <+12>: ldr r0, [r3, #0]
0x00000112 <+14>: subs r0, #1
0x00000114 <+16>: cmp r2, r0
0x00000116 <+18>: bcc.n 0x11a <F+22>
0x00000118 <+20>: pop {r4, pc}
0x0000011a <+22>: mov r0, r4
0x0000011c <+24>: bl 0x13c <strlen>
0x00000120 <+28>: b.n 0x118 <F+20>
0x00000122 <+30>: nop
0x00000124 <+32>: lsls r0, r3, #6
0x00000126 <+34>: movs r0, r0
Run Code Online (Sandbox Code Playgroud)
请注意,在文件长度比定义的长度短的情况下,不是仅仅通过$r2再次计算来获取其长度,而是使运行时间变得与 2* 文件长度一样长。这似乎没有必要。在这种情况下有什么方法可以证明编译器的行为是合理的吗?我有兴趣知道。
这是多余的。但这是因为你的代码,而不是编译器。该宏将扩展为:
// x = strlen(file)
// y = MAX_FILE_NAME - 1
(((strlen(file)) < (MAX_FILE_NAME - 1)) ? (strlen(file)) : (MAX_FILE_NAME - 1))
Run Code Online (Sandbox Code Playgroud)
请记住,预处理器本质上只是一个美化的复制和粘贴机器。你打了strlen两次电话。尝试这个:
size_t file_len = strlen(file);
file_len = MIN(file_len, MAX_FILE_NAME - 1);
Run Code Online (Sandbox Code Playgroud)