我有很多函數需要一個字符串作爲參數,爲此我使用char*
,但是所有期望字節數組的函數也使用char*
。區分字符串和字節數組?
問題是我可以很容易地在字符串函數中傳遞一個字節數組,導致各種溢出錯誤,因爲無法找到null終止符。
這是怎麼回事?我可以想象將所有的字節數組函數改爲uint8_t
,然後當我傳遞一個字符串時,編譯器會警告有關簽名的問題。或者這裏的正確方法是什麼?
我有很多函數需要一個字符串作爲參數,爲此我使用char*
,但是所有期望字節數組的函數也使用char*
。區分字符串和字節數組?
問題是我可以很容易地在字符串函數中傳遞一個字節數組,導致各種溢出錯誤,因爲無法找到null終止符。
這是怎麼回事?我可以想象將所有的字節數組函數改爲uint8_t
,然後當我傳遞一個字符串時,編譯器會警告有關簽名的問題。或者這裏的正確方法是什麼?
的問題在C更普遍比你所想。由於char*
和char[]
是等價爲函數的參數,這種參數可以是指三個不同的語義概念:
char
對象的指針(這是指針類型的「正式」的定義)char
陣列在是大多數情況下是可能的C標準的mondern接口使用void*
爲無類型字節AR ray,而且你應該遵守該慣例,並且僅對字符串使用char*
。
char[]
本身可能很少使用,我無法想象這些用例很多。如果你認爲它們是數字,你應該使用signed
或unsigned
變體,如果你看到它們,就像你應該選擇位模式unsigned char
一樣。
如果你真的是一個數組作爲函數的參數(char
與否)你可以清楚地表明它標誌着這一事實對你的代碼的普通讀者:
void toto(size_t n, char A[const n]);
這相當於
void toto(size_t n, char *const A);
但讓你的意圖更清晰。而且在未來,甚至可能會有工具來檢查你的邊界。
我一般做一個數組像下面
typedef struct {
unsigned char* data;
unsigned long length;
unsigned long max_length;
} array_t;
然後通過array_t *各地
,並創建採取array_t *
void array_create(array_t* a, unsgined long length) // allocates memory, sets the max_length, zero length
void array_add(array_t* a, unsigned char byte) // add a byte
等
可能會更好地使用'size_t'而不是'unsigned long' –
是的,你是對的 –
寫入陣列功能一個處理字符串和字節的通用結構。
struct str_or_byte
{
int type;
union
{
char *buf;
char *str;
}pointer;
int buf_length;
}
如果type
不是字符串,則訪問pointer.buf
只有高達buf_length
。否則直接訪問pointer.str
而不檢查buf_length
並將其保留爲空字符結束。
或者,通過僅考慮長度來維護字符串也作爲字節數組,不要將空字符串保留爲空字符串。
struct str_or_byte
{
char *buf;
int buf_length;
}
而且不使用不考慮長度的字符串manuplation函數。這意味着使用strncpy
,strncat
,strncmp
...而不是strcpy
,strcat
,strcmp
...
C使用約定。這裏是我使用的規則(在標準庫之後製作)
void foo(char* a_string);
void bar(void* a_byte_array, size_t number_of_bytes_in_the_array);
這很容易記住。如果你傳遞一個char * ptr,那麼它必須是一個以null結尾的char數組。
爲字節數組做一個包裝? –
@VaughanHilts我不明白這是如何解決我的問題? – Muis
一個字符串*是一個字節數組。既然你實際上不能在C中傳遞數組,但只有一個指向第一個元素的指針,你通常也必須傳遞一個大小。只需檢查數組是否包含零值。如果是這樣,那麼它是一個「字符串」。否則,它不是。 –