2016-02-15 19 views
0

我需要從第三方開發人員以乾淨的方式獲得固定長度的名稱(希望)不需要任何分配,並且編譯器檢查得很好。填充預先分配的固定大小的字符串作爲參數傳入C

我提供的原型是這樣的:

void getName(char name[9]); 

,他們會寫一個函數是這樣的:

void getName(char name[9]) { 
    strncat(_name, "Hello World", 8); 
} 

然後我把它(在我身邊)排序是這樣的:

char buf[9]; 
*buf = '\0'; 
getName(buf); 
doSomethingWith(buf); 

它編譯和似乎工作,但我不知道它處理這個最好的方法。

有什麼建議嗎?

編輯:爲了澄清,名稱字符串被用作壓縮二進制保存文件中的標識符。它需要正好8個ASCII 8位字符。

我想知道現在是否應該只收到任何字符串並截斷它在我身邊。我希望編譯器能幫忙,而不是運行時檢查。

+2

我期望一個名爲'getName'的函數來返回一些東西,而不是設置一些東西。我會把它稱爲'init_name'或'set_name'或其他東西。如果它是一個getter,我可以讓它返回一個新分配的(堆內存)'char *',或者返回一個'const char *'字符串常量 –

+1

主要的注意事項是getName(char name [9])'不會確保'getName()'只能用9個字符的緩衝區來調用。 *任何*'char *'都將滿足編譯器,即使是未初始化的編譯器,也會導致無效的內存訪問。 – DevSolar

+0

@DevSolar啊哈。那麼這是一個問題。它需要正好8個ASCII的汽車。它用作二進制保存文件中的標識符。 –

回答

2

在您的示例中,名稱是一個靜態字符串。在這種情況下,函數可能看起來像下面,在不需要額外的數據複製:

const char* getName(void) 
{ 
    return "Hello World"; 
} 

...

const char* const pName = getName(); 

或者:

void getName(FUNCPTR func) 
{ 
    func("Hello World"); 
} 

其中void func(const char* const pName)在實施你的身邊。那麼你也不需要分配/複製數據。

+0

是的。你應該避免使用具有明確大小的數組,除非你確定知道將數據拷入其中的大小。原始示例導致緩衝區溢出。 –

+0

我需要一個正好8個字符的字符串。它用作保存在打包數據文件中的標識符。 –

+1

你無論如何都需要檢查字符串是否包含8個字符(實際上它可能包含更少),對嗎?從這個角度來看,我個人認爲在這種情況下沒有使用顯式大小數組的好處,在上面的註釋中提到的@o_weisman只有更多的複雜性和緩衝區溢出的風險。 – dmi

0

你的第一份工作是同意返回字符串的數據類型。

儘管很容易使用char*,但由於char的類型沒有被標準(可以是無符號,有符號2的補碼或有符號1的補碼)沒有充分定義,所以您不應該這樣做。如果你不小心,你的程序的行爲可能是不確定的,如果你混淆了你的類型。 所以你應該決定一個類型,並相應地使用#DEFINE CharType

然後至於函數本身,不要依賴第三方來分配內存,除非您調用它們的庫來釋放內存。您的C運行時可能會使用不同的分配系統。爲了解決這個常見問題,一種約定已經成長:如果你通過NULL作爲輸出緩衝區,那麼第三方函數應該返回所需緩衝區的長度。然後你自己用所需的長度分配內存,並再次調用該函數,明確發送分配的緩衝區的大小。在該模式下,該函數返回分配的字符串的長度以及填充到緩衝區中的結果。

把所有這些組合起來,一個好的原型是

SizeType getName(CharType* buffer, SizeType length);

其中SizeType再次在您與第三方達成一致。一般來說,這是Windows API的工作原理。

+0

它是一個固定的8個字符的大小是一個要求。 8個字節的ASCII字符是精確的。它用作打包二進制保存文件中的標識符。 –

+0

@SamWashburn也許你可以截斷或填充8個字節。爲什麼它必須是ASCII? – Stuart

+0

@Stuart我可以截斷和填充,是的。我只是希望得到一些不是運行時檢查的東西,這可能會被編譯器捕獲,因爲使用太長的字符串可能是第三方的錯誤。至於ASCII,處理起來更容易。理論上,例如在UTF-8中,有可能有一個長度爲9個字節的字符串,最後一個字符是兩個字節,它們將被切成兩半。 –

相關問題