[英]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,編譯器將只會看到一個主 function,其return 0;
陳述。
該標准沒有規定在這個級別上應該發生什么。 如果您想知道您的編譯器和目標在您的特定情況下發生了什么,您將不得不查看程序集。
最可能的情況是它被完全刪除。 既因為編譯器甚至看不到它,又因為當你什么都不能產生時為什么要產生一個 nop 呢?
但是,我仍然想知道是否將程序閃存到 ARM 微控制器(帶有 arm_gcc)上,那條線會變成 nop 操作嗎?
沒有比測試更簡單的了!
$ 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
指令。 只是應該在那里的說明。
那條線會變成nop操作嗎?
不,那條線將“不存在”。
您可以在編譯器資源管理器中查看: https://gcc.godbolt.org/z/39Koxz
這里可以看到主function編譯下來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;
}
如您所見,最終代碼只是一個返回 0 的空主代碼。
既然沒有代碼生成一個操作,為什么它不變成一個空操作(就像不消耗 CPU 周期一樣)? 如果它是一個 nop,那是否意味着它需要 1 個 CPU 周期?
空語句沒有可觀察到的效果 - 因此不會生成代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.