2013-10-29 57 views
1

當創建預期輸入C函數,我傾向於做這樣的:有沒有辦法預先定義C函數參數的預期長度?

function(unsigned char *bytes, unsigned int bytelen) { … 

現在,我有一個項目我編碼,其中這樣的功能期待的正是256的無符號的特定bytelen功能字符。

所以,我想這似乎工作如下:

function(unsigned char bytes[256]) { … 

然而,測試一個(使用GCC),它不會在編譯的時候,當我經過1024個無符號字符的功能失效。將printf添加到該函數中,它甚至可以毫無問題地打印這些1024個無符號字符。

這不是我所期望的或意圖的,因爲 - 最終 - 功能表現得好像我會用function(unsigned char *bytes) { …

當然,我可以進行通常的健全性檢查,看看是否通過了期望的長度,如果輸入不完全是256個字符,程序性失敗。但是沒有一種方法可以在函數的參數中明確地預定義該限制嗎? (還是我做錯了。如果,我將不勝感激,我錯在何處擡頭?)

+2

可以傳遞具有'無符號字符字節[256]'字段的結構的地址。 – chux

回答

3

那不是我預期的或希望的,因爲 - 最後 - 函數的行爲就像我會使用函數(無符號字符*字節){...

您的評論是絕對正確的。在函數參數列表中寫入unsigned char bytes[1024]完全相同在C中爲unsigned char *bytes。它的工作原理和行爲方式完全相同。

但是沒有一種方法可以在函數的參數中顯式地預定義極限嗎?

不在C.你可以做的就是定義一個struct其中具有固定大小的數組:

typedef struct { 
    unsigned char buffer[1024]; 
} arraytype; 

,然後你可以使用arraytype *爲你的函數參數類型,這樣你的編譯器,然後讓它確定實際的函數調用使用正確類型的指針arraytype *。當然,你然後不能通過一個純粹的unsigned char陣列,你必須使用arraytype

+1

「,然後你可以使用arraytype *作爲你的函數參數類型」如果你打算這樣做,你可能有參數是'無符號字符(* foo)[1024]',而不用去定義一個新類型。 – newacct

2

數組衰變爲指針的函數,將數組大小,以及這樣的:

function(unsigned char bytes[], unsigned int bytelen)

型陣列的-T的左值出現在表達衰減(與 三個例外)到一個指針到它的第一元件; 結果指針的類型是指向T的指針。

(唯一的例外是當陣列是的sizeof或&運營商的操作數,或者是一個字符數組一個字符串初始化。)

+1

這不是關於*數組衰減到指針*語義,儘管它是密切相關的。更確切地說,**僅在參數列表**中,對於任何類型T和恆定正整數N,將聲明T a [],T a [N]和T * a定義爲相同,也就是說,它們都意味着'T * a'。 –

+2

OP:IOW,當編譯器在函數參數列表(僅在那裏)看到'unsigned char bytes [256]'時,它靜靜地將其同樣視爲'unsigned char * bytes'。這實際上是添加到C故意讓它更「直觀」: -/ –

1

在C中,N個東西的數組是N個東西的連續存儲塊。這並不比設計更復雜。因此,如果s指向1024個字符的數組的開頭,那麼它也指向1023個事物的數組的開始,或者256個事物或3個事物。並且s+1,s+400s+768(或者&s[1],&s[400]&s[768],它們是精確等價的)也指向256個數組的開始。

無論如何,編譯器不太可能會爲你檢查這個東西,儘管它可能。

如果你想討論這正好有256個字符,而不是更多,而不是更少,把它包裝成一個結構對象:

struct TwoFiveSix { 
    char s[256]; 
}; 

如果你的函數的原型說,它需要一個struct TwoFiveSix的地址,編譯器肯定會抱怨,如果你試圖通過它別的東西。就像一個字符串。

0

你是怎麼調用這個函數的?想象一下這樣的:

void f() 
{ 
    const char* p = get_a_line_from_file(); 
    function(p); 
} 

假設get_a_line_from_file()回報不過多少數據是在運行時的文件中,有明確沒有辦法編譯器在編譯時知道該字符串是否將是256個字符或沒有。

在另一方面,在...

char local_buffer[256]; 
populate(local_buffer, sizeof local_buffer); 
function(local_buffer); 

...這將是可能的編譯器,以驗證在編譯時本地緩存的大小。如果你想要的,你需要做這樣的功能雖然調用之前,如:

#define FUNCTION(X) do { STATIC_ASSERT(sizeof local_buffer == 256); function_impl(x); } while (false) 

這是假設,如果包含的表達式是不是靜態確定爲真產生一個錯誤的支撐宏觀STATIC_ASSERT - 你毫無疑問可以在網上找到很多很好的實現。 do - while成語通常由宏使用,以確保它們在if - else子句中以單行語句正常工作。

有這方面的一個問題是,如果緩衝區是不是本地的,你需要依傍直接調用執行,如:

void g(const char* p) 
{ 
    function_impl(p); 
} 

void h() 
{ 
    char local_buffer[256]; 
    g(local_buffer); 
} 

總而言之,它不可能是值得的努力編譯時驗證。

如果內容是ASCIIZ/NUL-delimited,那麼無論如何你可能需要一個運行時間strlen()驗證。

(在C++中可以驗證這一點使用template <size_t N> void function(const char (&param)[N]) { ... }

相關問題