1
4

4 回答 4

3

这不是我的预期或意图,因为 - 最后 - 该函数的行为就像我会使用 function(unsigned char *bytes) {...

你的话完全正确。在 C 中的编写unsigned char bytes[1024]与在函数参数列表中的编写完全相同。unsigned char *bytes它的工作方式和行为方式完全相同。

但是没有办法在函数的参数中显式地预定义该限制吗?

不在 C 中。您可以做的是定义一个结构,其中包含固定大小的数组:

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

然后您可以将arraytype *其用作您的函数参数类型,以便您的编译器确保实际的函数调用使用正确类型的arraytype *指针。当然,你不能传递一个裸unsigned char数组,你必须使用arraytype.

于 2013-10-29T02:12:34.397 回答
2

数组衰减为函数中的指针,传递数组大小,如下所示:

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

出现在表达式中的 T 数组类型的左值衰减(除了三个例外)成指向其第一个元素的指针;结果指针的类型是指向 T 的指针。

(例外情况是数组是 sizeof 或 & 运算符的操作数,或者是字符数组的文字字符串初始值设定项。)

于 2013-10-29T02:04:57.590 回答
1

在 C 中,包含 N 个事物的数组是包含 N 个事物的连续存储块。按照设计,它没有比这更复杂的了。因此,如果s指向 1024 个字符的数组的开头,那么它也指向 1023 个、256 个或 3 个对象的数组的开头。And s+1, s+400and s+768(或&s[1], &s[400]and &s[768],它们完全等价)也指向一个包含 256 个事物的数组的开头。

无论如何,编译器不太可能为您检查这些内容,尽管它可能会。

如果你想讨论一个正好有 256 个字符的对象,不多不少,把它包装成一个结构:

struct TwoFiveSix {
  char s[256];
};

如果您的函数原型说它需要 a 的地址,struct TwoFiveSix那么如果您尝试传递其他东西,编译器肯定会抱怨。像一根弦。

于 2013-10-29T02:13:00.387 回答
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中的单行语句正常工作。ifelse

这样做的一个问题是,如果缓冲区不是本地的,则需要直接调用实现,如下所示:

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

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

总而言之,编译时验证的努力不太值得。

如果内容是 ASCIIZ / NUL 分隔的,那么您可能无论如何都需要运行时strlen()验证。

(在 C++ 中,您可以使用 来验证这一点template <size_t N> void function(const char (&param)[N]) { ... }

于 2013-10-29T05:38:31.620 回答