2017-02-16 45 views
2

當我編寫代碼時,我嘗試通過創建「模塊」來保持程序的邏輯上可分割的部分分離。來自諸如Javascript和NodeJS或Python之類的語言來實現這一點非常簡單。有了C,我已經找到了一些方法來完成這個模式,我提供了一個下面的例子。我使用靜態方法聲明與const聲明結構來創建「模塊」來組織我的代碼。我可以讓編譯器優化結構中的函數調用嗎?

我注意到用這種技術調用方法的成本通常只是每個調用一個彙編指令。

而不是

movl -8(%rbp), %edx 
movl -12(%rbp), %eax 
movl %edx, %esi 
movl %eax, %edi 
call my_add_method 

「模塊」技術將產生

movl $my_add_method, %ecx 
movl -8(%rbp), %edx 
movl -12(%rbp), %eax 
movl %edx, %esi 
movl %eax, %edi 
call *%rcx 

我想找到被宣佈這些模塊的方式,但有編譯後的輸出是相同的,只是調用方法由它的直接名稱。

我想知道的是:

  1. 有沒有一種方法可以讓編譯器(GCC),無論是與標誌或聲明的結構不同,優化代碼,這樣所產生的ASM是一樣?

  2. 我想這將是簡單編譯器優化的事情,如果沒有方法存在,爲什麼這種優化通常不可能? (考慮到結構都不變和靜態)


/** 
* File: main.c 
* Target: x86_64-linux-gnu 
* Compile: gcc main.c -S -o main 
*/ 
#include <stdio.h> 

typedef struct { 
    int (* const add_func)(int, int); 
} MY_MOD_T; 

static int my_add_method(int a, int b) { 
    return a+b; 
} 

const MY_MOD_T Module = { 
    .add_func = my_add_method 
}; 

int main(void) { 
    int a = 5; 
    int b = 6; 

    // substitute these two lines to see the different output like above 
    int result = Module.add_func(a, b); 
    //int result = my_add_method(a, b); 

    printf("%d + %d = %d\n", a, b, result); 
    return 0; 
} 
+0

您能否可靠地檢測到性能差異? –

+2

您是否嘗試過使用優化標誌(-O)?輸出將會非常不同。嘗試優化'-O0'中的asm輸出可能是徒勞無益的。 – Jahaja

+0

不,這不是一個表現問題,只是一種好奇心。我只是認爲這對編譯器優化來說是一件簡單的事情。 – MatUtter

回答

1

在一般情況下,是不可能使通過函數指針的行爲函數調用相同,以調用名爲功能。

在您的例子,考慮一個頭文件module_interface.h

typedef struct { 
    int (* const add_func)(int, int); 
} MY_MOD_T; 

稱爲module_derived.h不同的頭文件:

#include "module_interface.h" 

extern const MY_MOD_T Module; 

module_derived.c派生模塊的實現:

#include "module_derived.h" 

static int my_add_method(int a, int b) { 
    return a+b; 
} 

const MY_MOD_T Module = { 
    .add_func = my_add_method 
}; 

int module_add_method(int a, int b) { 
    return my_add_method(a, b); 
} 

然後,你的主程序會l OOK,如:

#include <stdio.h> 
#include "module_derived.h" 

extern int module_add_method(int a, int b); 

int main(void) { 
    int a = 5; 
    int b = 6; 

    // substitute these two lines to see the different output like above 
    int result = Module.add_func(a, b); 
    //int result = module_add_method(a, b); 

    printf("%d + %d = %d\n", a, b, result); 
    return 0; 
} 

如果module_derived實際上是一個共享庫,是不是真的有一個優化級別,可以幫助克服函數指針值必須取消引用的事實。在-O3

# Calling named function
movl $6, %esi
movl $5, %edi
call module_add_method
# Calling through module
movl $6, %esi
movl $5, %edi
call *Module(%rip)

正如您所看到的,在通過模塊機制時會出現額外的偏移量計算和取消引用。

但是,對於共享庫,此模塊開銷與位置獨立代碼(PLT和GOT開銷)所帶來的開銷相當。所以,在實踐中,除非分析告訴你,否則開銷不值得擔心。在這種情況下,你必須考慮找到一種內聯熱門函數調用的方法。

+0

使用''-shared'''可以解釋爲什麼即使在使用-O時我也看到了不同的輸出,謝謝! – MatUtter

相關問題