2015-08-18 181 views
1

我發現自己使用函數參數輸入和輸出,並想知道我在做什麼會咬我以後。使用函數參數作爲輸入和輸出

在這個例子中buffer_len就是這樣一個參數。 foo使用它來確定緩衝區的大小,並告訴調用者main有多少緩衝區已用完。

#define MAX_BUFFER_LENGTH 16 
char buffer[MAX_BUFFER_LENGTH] = {0}; 

void main(void) 
{ 
    uint32_t buffer_len = MAX_BUFFER_LENGTH; 

    printf("BEFORE: Max buffer length = %u", buffer_len); 

    foo(buffer, &buffer_len); 

    printf("BEFORE: Buffer length used = %u", buffer_len); 
} 

void foo(char *buffer, uint32_t *buffer_len) 
{ 
    /* Remember max buffer length */ 
    uint32_t buffer_len_max = *buffer_len; 
    uint32_t buffer_len_left = buffer_len_max; 

    /* Add things to the buffer, decreasing the buffer_len_left 
     in the process */ 
    ... 

    /* Return the length of the buffer used up to the caller */ 
    *buffer_len = buffer_len_max - buffer_len_left; 
} 

這是一件好事嗎?

編輯:

謝謝您的答覆,但我寧願保持foo的返回值的實際功能的結果(這使得具有較大功能意義上的)。從長遠來看,這樣的事情會更無痛嗎?

typedef struct 
{ 
    char *data_ptr; 
    uint32_t length_used; 
    uint32_t length_max; 
} buffer_t; 

#define ACTUAL_BUFFER_LENGTH 16 
char actual_buffer[ACTUAL_BUFFER_LENGTH] = {0}; 

void main(void) 
{ 
    buffer_t my_buffer = { .data_ptr = &actual_buffer[0], 
          .length_used = 0, 
          .length_max = ACTUAL_BUFFER_LENGTH }; 
} 
+1

只要有文件記錄,它就是「OK」,但它確實不是首選的操作方式。爲什麼不讓函數返回所用的長度,並將緩衝區長度參數保留爲常規的'uint32_t'(或者'size_t',這樣你就可以將'sizeof(buffer)'傳遞給函數)? –

+2

它在語法上沒問題,但我個人更喜歡返回代碼。如果這是不可能的,我想要一個*專用*輸出參數,尤其是*,如果它是通過引用傳遞。 (我可能沒有注意並繼續假設我的'buffer_len'仍然保持原始值。) – DevSolar

+1

只要你還沒有用完你的返回值,我更喜歡接收結果,而不是每次使用函數(或者我想輸入一個表達式)時都必須定義一個變量。 – BeyelerStudios

回答

3

對於原始版本的問題,其中所調用的函數沒有返回值,你有三個類似的答案,都大致說:「是的,但是......」:

Jonathan Lefflersaid

只要有文件記錄,它就是「OK」,但它確實不是首選的操作方式。爲什麼不讓函數返回所用的長度,並將緩衝區長度參數保留爲常規uint32_t(或者可能是size_t,因此您可以將sizeof(buffer)傳遞給函數)?

DevSolarsaid

這句法OK,但我個人更喜歡返回代碼。如果這是不可能的,我想要一個專用的輸出參數,特別是如果它是通過引用傳遞的話。 (我可能沒注意,我的buffer_len仍然保持着原始值的假設下繼續。)

BeyelerStudiossaid

只要你沒有使用你的返回值,我更喜歡接收結果,而不是每次使用函數時(或者我想輸入表達式)定義一個變量。

一致是顯着的。

然後問題被更新以表明不是返回void,函數的返回值將被用於其他目的。這完全改變了評估。

如果您的實際功能要返回值,則不要顯示void函數。這樣做完全改變了答案。如果您需要返回多個值,則輸入輸出參數爲OK(即使有必要 - getchar()是一個反例),但純參數和單獨的純輸出參數可能會更好。使用結構也可以。

也許我應該解釋一下'反例'。 getchar()函數返回一個值,指示失敗或值爲char。這導致了初學者的許多陷阱(因爲getchar()返回一個int,而不是char顧名思義)。這將是更好,在某些方面,如果函數是:

bool get_char(char *c); 

返回true如果讀入一個字符和false如果失敗,和字符值賦給c。它可以用於:

char c; 
while (get_char(&c)) 
    …use character just read… 

這是函數需要返回兩個值的情況。

重新回到建議的修改後的代碼中,代碼使用了結構。

這根本不是一個壞主意;將一組數值打包到一個結構中通常是明智的。如果被調用的函數必須計算它將返回的某個值,它會很有意義,但它也會修改緩衝區數組,並需要報告其中的條目數(以及知道有多少空間使用)。在這裏,保持「可用空間」與「使用空間」分離是絕對可取的;看到發生了什麼比擁有「進出」參數更容易,該參數告知功能進入時有多少空間可用,並報告退出時使用了多少空間。即使它報告出口仍有多少空間可用,但使用起來會更困難。

回到原始診斷:是的,輸入輸出參數在技術上是合法的,並且可以工作,但並不像單獨的值那麼容易。


旁註:void main(void)是不寫main()的標準方法 - 看What should main() return in C and C++?完整故事。

1

沒有什麼錯誤使用的輸入和輸出相同的緩衝區,但它可能在其他地方限制了功能實用。例如,如果你想使用兩個不同的值呢? (由於某些原因,我需要保留原始的函數)。在你提供的例子中,在函數中使用兩個參數沒有什麼壞處,然後只傳入兩次相同的指針。然後你已經包裝了這兩個用途,它可能簡化了功能代碼。

對於更復雜的數據類型(如數組),以及上述相同的問題,您需要確保您的函數不需要更大的輸出,或者如果它縮小memset(0 ..)的緩衝區)的區別等等。

因此,對於這些頭痛,我傾向於避免作爲一種模式,但正如我所說的沒有什麼特別的錯誤。

相關問題