我有很多函数希望字符串作为参数,我使用char*
,但我所有期望字节数组的函数也使用char*
。
问题是我很容易犯错误,在字符串函数中传递一个字节数组,导致各种溢出,因为无法找到空终止符。
这通常如何解决?我可以想象将我的所有字节数组函数更改为uint8_t
,然后编译器会在传递字符串时发出有关signed-ness的警告。或者这里的正确方法是什么?
答案 0 :(得分:2)
我通常会制作类似以下内容的数组
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
等
答案 1 :(得分:1)
C中的问题比你想象的更为普遍。由于char*
和char[]
对于函数参数是等价的,因此这样的参数可以引用三种不同的语义概念:
char
对象上的指针(这是"官方"指针类型的定义)char
数组在大多数情况下,C标准中的mondern接口使用void*
作为无类型字节数组,您应该遵守该约定,并且仅对字符串使用char*
。 / p>
char[]
本身可能很少使用;我无法想象这些的大量用例。如果您将它们视为数字,则应使用signed
或unsigned
变体,如果您看到它们,则应选择位模式unsigned char
。
如果您真的将数组表示为函数参数(char
或不是),您可以通过清楚地指出代码的随意读者来标记该事实:
void toto(size_t n, char A[const n]);
这相当于
void toto(size_t n, char *const A);
但让你的意图更清晰。在未来甚至可能有工具为你做边界检查。
答案 2 :(得分:0)
编写一个通用结构来处理字符串和字节。
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;
}
并且不要使用不考虑长度的字符串制作功能。这意味着使用strncpy
,strncat
,strncmp
...代替strcpy
,strcat
,strcmp
......
答案 3 :(得分:0)
C使用惯例。这是我使用的规则(在std lib之后制作)
void foo(char* a_string);
void bar(void* a_byte_array, size_t number_of_bytes_in_the_array);
这很容易记住。如果你传递一个char * ptr,那么它必须是一个以null结尾的char数组。