簡體   English   中英

這個聲明會變成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,編譯器將只會看到一個主 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM