2014-04-05 126 views
1

下面我有一些代碼可以做同樣的事情並給出相同的輸出。在第一個中,我使用了指針參數傳遞指針來消除使用全局的ans。在第二個,我發ans全局與指針處理,以指針時消除*的附加用途:指針或全局變量的指針?

實施例1:

// pointer to pointer 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 

unsigned char serial[] = { 
    0x1,0x2,0x3,0x4 
}; 

void checkSerial(unsigned char* buf, unsigned char ** ans) 
{ 
    int i; 
    unsigned char *part; 

    part = 0; 
    i=2; 

    part = &buf[i]; 

    *ans = (unsigned char*)malloc(2); 
    memset(*ans,0,2); 
    memcpy(*ans,part,2); 
    printf("0x%x\n",**ans); 
    ++(*ans); 
    printf("0x%x\n",**ans); 
} 

int main(void) 
{ 
    unsigned char *ans, *buf; 

    while(1) 
    { 


     buf = malloc(4); 
     memset(buf,0,4);  
     memcpy(buf, serial, sizeof(serial)); 

     checkSerial(buf, &ans); 
     --ans; 
     printf("the value is 0x%x\n", *ans); 
     free(buf); 
     free(ans); 

     sleep(3); 
    } 
    return 0; 
} 

實施例2:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 

unsigned char serial[] = { 
    0x1,0x2,0x3,0x4 
}; 

unsigned char ans[2]; 

void checkSerial(unsigned char* buf) 
{ 
    int i; 
    unsigned char *part; 

    part = 0; 
    i=2; 

    part = &buf[i]; 

    int j; 
    for(j=0;j<2;j++) 
    { 
     ans[j] = part[j]; 
    } 

    printf("0x%x\n",*ans); 
    ++(*ans); 
    printf("0x%x\n",*ans); 
} 

int main(void) 
{ 
    unsigned char *buf; 

    while(1) 
    { 


     buf = malloc(4); 
     memset(buf,0,4);  
     memcpy(buf, serial, sizeof(serial)); 

     checkSerial(buf); 

     printf("the value is 0x%x\n", *ans); 
     free(buf); 

     sleep(3); 
    } 
    return 0; 
} 

哪種技術是首選C?

+2

我個人也不會使用。你已經在while循環中分配了buf來傳入序列號,所以id也在while循環中分配了ans,並將其傳遞到checkSerial中以填充。此外,你的全局ans不夠大,不足以適應它的答案只有1個字節不是2. – Dampsquid

+0

你確定要用'--ans;'......減少'ans'指針嗎?可能你的意思是減少一個值得考慮的價值,那就是' - * ans;'...? – CiaPan

+0

儘管不推薦使用全局變量,但如果變量的分配距離很遠,則創建指向指針的指針會在彙編級別創建兩個間接級別。如果這些變量未緩存在單個緩存中,則這可能會導致性能損失線導致處理器停頓並計算第二個變量的地址並將該變量/高速緩存線置於其上進行操作。 – Recker

回答

3

當不需要時避免使用全局變量。以第一個例子爲例更好。

全局變量很容易被每個函數訪問,它們可以被程序的任何部分讀取或修改,因此很難記住或推論每個可能的用途。

+0

我認爲你的意思是第一個例子,第二個是具有全局變量的例子。 –

+0

另外,如果返回的指針必須被調用者釋放,我希望讀取函數原型評論告訴我。 –

+0

@Étienne;哎呀!更正了:) – haccks

0

我個人不喜歡在有辦法避免它的地方定義全局變量。

但有些人說,指針的概念非常混亂。我不覺得雖然..

我的建議,如果你與指針混淆嘗試避免與定義全局變量。否則,請使用指針... :)

+4

指針是每個非平凡編程技術的支柱。他們必須解決一個不可避免的問題。 – StoryTeller

1

保持變量儘可能接近它們的使用範圍。這可以防止您的變量和潛在命名問題的意外值。

0

TL; DR:解決方案1和2都不好。

你寫這個例子的方式讓malloc無用,因爲你知道在編譯時ans和buf的大小,如果那些在編譯時真的知道的話,就根本不使用malloc,聲明變量堆棧。在C中,通常儘可能避免動態內存分配,並且傾向於創建可以保存緩衝區在應用程序中可以具有的最大大小的緩衝區。這首先避免了這種問題。您編寫示例的方式使得malloc無用,因爲您知道編譯時的大小爲ansbuf。動態內存分配唯一有用的地方是在編譯時大小未知的緩衝區,但仍然可以避免它(見下文)。如果buf是傳入消息,並且ans對此消息的回答,編譯時可能不知道ans的大小,至少如果使用可變長度消息。

您的版本2不工作,無法工作!首先你聲明ans是一個大小爲1的數組,並遍歷它直到索引2(現在你編輯它)。其次,要將數組ans聲明爲全局的,您需要在編譯時瞭解它的大小,然後當然如果您在編譯時知道它的大小,則只需在函數checkSerial中聲明數組ans即可。此外,當你聲明一個變量被C中的幾個函數使用時,不要忘記聲明它是靜態的,否則它可以從項目中的所有文件中訪問。

一個解決方案,避免動態分配,注意避免您使用2個解決方案的缺點:指針,指針和全局變量,而且你的程序不能漏,因爲你不使用動態分配:

enum {MSG_MAX_SIZE = 256 }; 
typedef struct message { 
    uint8_t payload[MSG_MAX_SIZE]; 
    size_t msg_size; 
} message_t; 

void checkSerial(const message_t *buf, message_t *ans) 
{ 
    //parse buf and determine size of answer 
    ... 
    ... 
    //fill answer payload 
    ans->msg_size = buf[42]; 
} 

int main(void) 
{ 
    while (1) { 
     message_t buf; 
     getMsg(&buf); 
     message_t ans; 
     checkSerial(&buf, &ans); 
    } 
}