6

我有很多函数需要一个字符串作为参数,为此我使用char*,但我所有需要字节数组的函数也使用char*.

问题是我很容易犯在字符串函数中传递字节数组的错误,导致各种溢出,因为找不到空终止符。

这通常是如何处理的?我可以想象将我所有的字节数组函数都更改为uint8_t,然后编译器会在我传递一个字符串时发出有关签名的警告。或者这里的正确方法是什么?

4

4 回答 4

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

ETC

于 2013-02-02T20:49:04.483 回答
1

这个问题在 C 中比你想象的更普遍。由于char*char[]等价于函数参数,因此这样的参数可以指代三个不同的语义概念:

  • 一个char对象上的指针(这是指针类型的“官方”定义)
  • 一个char数组
  • 一个字符串

在大多数情况下,C 标准中的现代接口可能void*用于无类型字节数组,您可能应该遵守该约定,并且char*仅用于字符串。

char[]本身可能很少这样使用;我无法想象这些有很多用例。如果您将它们视为数字,您应该使用signedorunsigned变体,如果您将它们视为位模式unsigned char应该是您的选择。

如果您真的将数组作为函数参数(char或不是),您可以通过清楚地指示来为您的代码的临时读者标记该事实:

void toto(size_t n, char A[const n]);

这相当于

void toto(size_t n, char *const A);

但会让你的意图更清晰。将来甚至可能会有工具为您进行边界检查。

于 2013-02-02T21:37:53.927 回答
0

C 使用约定。这是我使用的规则(在标准库之后流行)

void foo(char* a_string);

void bar(void* a_byte_array, size_t number_of_bytes_in_the_array);   

这很容易记住。如果您传递单个 char* ptr,则它必须是一个以 null 结尾的 char 数组。

于 2013-02-03T04:01:36.037 回答
0

编写一个通用结构来处理字符串和字节。

struct str_or_byte
{
    int type;
    union
    {
        char *buf;
        char *str;
    }pointer;
    int buf_length;
}

如果type不是字符串,则访问pointer.buf唯一的 upto buf_length。否则直接访问pointer.str而不检查buf_length并将其维护为空终止字符串。

或者通过仅考虑长度将字符串也维护为字节数组,不要为字符串保留以空字符结尾的字符。

struct str_or_byte
{
    char *buf;
    int buf_length;
}

并且不要使用不考虑长度的字符串操作函数。这意味着使用strncpy, strncat, strncmp... 而不是strcpy, strcat, strcmp...

于 2013-02-02T20:50:21.480 回答