这个语句会变成 nop 吗?
Does this statement turn into a nop?
我想知道下面的代码在 #define PRINT_STATEMENT
行被注释掉后是否会在 ARM 微控制器上执行许多 CPU 个周期:
#define PRINT_STATEMENT 1
#if PRINT_STATEMENT
#define PRINT_DBG(...) printf(__VA_ARGS__)
#else
#define PRINT_DBG(...)
#endif
int main(){
PRINT_DBG("Hello World\n");
return 0;
}
我测试了在在线 C 编译器上注释掉 #define PRINT_STATEMENT
行,可以看到打印语句没有被执行。但是,我仍然想知道如果将程序闪存到 ARM 微控制器上(arm_gcc),那行会变成 nop
操作吗?
谢谢!
编译器可以自由决定是否产生 nop。生成任何不打印任何内容的程序几乎是免费的。
在现代编译器中,预处理和编译是同时进行的。但理论上,编译器在预处理器之后得到代码。在这种情况下,假设您已将 PRINT_STATEMENT
设置为 0,编译器将只会看到带有单条 return 0;
语句的主函数。
该标准并未规定在此级别上应该发生什么。如果你想知道你的编译器和你的目标在你的特定情况下发生了什么,你将不得不看一下程序集。
最有可能的情况是它被完全删除。一方面是因为编译器甚至看不到它,另一方面是因为当你什么都不能产生时为什么要产生一个 nop?
你可以在编译器资源管理器中查看:https://gcc.godbolt.org/z/39Koxz
这里可以看到主函数编译到return 0;
部分
如果您将 #define PRINT_STATEMENT
注释掉,则 printf 永远不会进入后期编译阶段。
我们可以使用 gcc -E
运行预处理器并打印结果来验证这一点:
$ gcc -E test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "test.c"
# 9 "test.c"
int main(){
;
return 0;
}
如您所见,最终代码只是一个带有 return 0 的空主代码。
Since there is no code to generate an operation, why does it not turn
into an empty operation (as in consuming no CPU cycles)? If it is a
nop, that would mean that it would take 1 CPU cycle?
空语句没有可观察到的效果 - 因此没有生成代码。
However, I am still wondering if the program were to be flashed onto an ARM microcontroller (with arm_gcc), will that line be turned into a nop operation?
没有比测试更简单的了!
$ cat main.c
#include <stdio.h>
#if PRINT_STATEMENT
#define PRINT_DBG(...) printf(__VA_ARGS__)
#else
#define PRINT_DBG(...)
#endif
int main(){
PRINT_DBG("Hello World\n");
return 0;
}
让我们看看 printf
调用:
$ arm-none-eabi-gcc -specs=nosys.specs -DPRINT_STATEMENT=1 main.c -o a.elf
$ arm-none-eabi-objdump -D a.elf | sed '/<main>:/,/^$/!d'
0000820c <main>:
820c: e92d4800 push {fp, lr}
8210: e28db004 add fp, sp, #4
8214: e59f0014 ldr r0, [pc, #20] ; 8230 <main+0x24>
8218: eb0000cc bl 8550 <puts>
821c: e3a03000 mov r3, #0
8220: e1a00003 mov r0, r3
8224: e24bd004 sub sp, fp, #4
8228: e8bd4800 pop {fp, lr}
822c: e12fff1e bx lr
8230: 0000b5fc strdeq fp, [r0], -ip
哎呀!看起来 printf
已优化为 puts
, 甚至 已禁用优化。好吧,不管怎样,让我们看看没有那个讨厌的东西printf
:
$ arm-none-eabi-gcc -specs=nosys.specs main.c -o b.elf
$ arm-none-eabi-objdump -D b.elf | sed '/<main>:/,/^$/!d'
0000820c <main>:
820c: e52db004 push {fp} ; (str fp, [sp, #-4]!)
8210: e28db000 add fp, sp, #0
8214: e3a03000 mov r3, #0
8218: e1a00003 mov r0, r3
821c: e28bd000 add sp, fp, #0
8220: e49db004 pop {fp} ; (ldr fp, [sp], #4)
8224: e12fff1e bx lr
里面没有nop
指令。只是应该存在的说明。
will that line be turned into a nop operation?
没有。该行将“不存在”。
我想知道下面的代码在 #define PRINT_STATEMENT
行被注释掉后是否会在 ARM 微控制器上执行许多 CPU 个周期:
#define PRINT_STATEMENT 1
#if PRINT_STATEMENT
#define PRINT_DBG(...) printf(__VA_ARGS__)
#else
#define PRINT_DBG(...)
#endif
int main(){
PRINT_DBG("Hello World\n");
return 0;
}
我测试了在在线 C 编译器上注释掉 #define PRINT_STATEMENT
行,可以看到打印语句没有被执行。但是,我仍然想知道如果将程序闪存到 ARM 微控制器上(arm_gcc),那行会变成 nop
操作吗?
谢谢!
编译器可以自由决定是否产生 nop。生成任何不打印任何内容的程序几乎是免费的。
在现代编译器中,预处理和编译是同时进行的。但理论上,编译器在预处理器之后得到代码。在这种情况下,假设您已将 PRINT_STATEMENT
设置为 0,编译器将只会看到带有单条 return 0;
语句的主函数。
该标准并未规定在此级别上应该发生什么。如果你想知道你的编译器和你的目标在你的特定情况下发生了什么,你将不得不看一下程序集。
最有可能的情况是它被完全删除。一方面是因为编译器甚至看不到它,另一方面是因为当你什么都不能产生时为什么要产生一个 nop?
你可以在编译器资源管理器中查看:https://gcc.godbolt.org/z/39Koxz
这里可以看到主函数编译到return 0;
部分
如果您将 #define PRINT_STATEMENT
注释掉,则 printf 永远不会进入后期编译阶段。
我们可以使用 gcc -E
运行预处理器并打印结果来验证这一点:
$ gcc -E test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "test.c"
# 9 "test.c"
int main(){
;
return 0;
}
如您所见,最终代码只是一个带有 return 0 的空主代码。
Since there is no code to generate an operation, why does it not turn into an empty operation (as in consuming no CPU cycles)? If it is a nop, that would mean that it would take 1 CPU cycle?
空语句没有可观察到的效果 - 因此没有生成代码。
However, I am still wondering if the program were to be flashed onto an ARM microcontroller (with arm_gcc), will that line be turned into a nop operation?
没有比测试更简单的了!
$ cat main.c
#include <stdio.h>
#if PRINT_STATEMENT
#define PRINT_DBG(...) printf(__VA_ARGS__)
#else
#define PRINT_DBG(...)
#endif
int main(){
PRINT_DBG("Hello World\n");
return 0;
}
让我们看看 printf
调用:
$ arm-none-eabi-gcc -specs=nosys.specs -DPRINT_STATEMENT=1 main.c -o a.elf
$ arm-none-eabi-objdump -D a.elf | sed '/<main>:/,/^$/!d'
0000820c <main>:
820c: e92d4800 push {fp, lr}
8210: e28db004 add fp, sp, #4
8214: e59f0014 ldr r0, [pc, #20] ; 8230 <main+0x24>
8218: eb0000cc bl 8550 <puts>
821c: e3a03000 mov r3, #0
8220: e1a00003 mov r0, r3
8224: e24bd004 sub sp, fp, #4
8228: e8bd4800 pop {fp, lr}
822c: e12fff1e bx lr
8230: 0000b5fc strdeq fp, [r0], -ip
哎呀!看起来 printf
已优化为 puts
, 甚至 已禁用优化。好吧,不管怎样,让我们看看没有那个讨厌的东西printf
:
$ arm-none-eabi-gcc -specs=nosys.specs main.c -o b.elf
$ arm-none-eabi-objdump -D b.elf | sed '/<main>:/,/^$/!d'
0000820c <main>:
820c: e52db004 push {fp} ; (str fp, [sp, #-4]!)
8210: e28db000 add fp, sp, #0
8214: e3a03000 mov r3, #0
8218: e1a00003 mov r0, r3
821c: e28bd000 add sp, fp, #0
8220: e49db004 pop {fp} ; (ldr fp, [sp], #4)
8224: e12fff1e bx lr
里面没有nop
指令。只是应该存在的说明。
will that line be turned into a nop operation?
没有。该行将“不存在”。