有没有办法预定义C函数参数的预期长度?

时间:2013-10-29 02:02:44

标签: c parameters parameter-passing

在创建期望输入的C函数时,我倾向于这样做:

function(unsigned char *bytes, unsigned int bytelen) { …

现在,我在一个正在编码的项目中有一个函数,其中这样的函数需要特定的bytelen正好256个无符号字符。

所以,我尝试了以下似乎有效的方法:

function(unsigned char bytes[256]) { …

然而,测试(使用GCC),当我将1024个无符号字符传递给函数时,它在编译时不会失败。在该函数中添加printf,它甚至可以打印出那些1024个无符号字符而没有问题。

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

当然,我可以进行通常的健全性检查,看看预期的长度是否通过,如果输入不是256个字符,则编程失败。但是,有没有办法在函数的参数中明确预定义该限制? (或者我做错了吗?如果,我会很高兴看到我错了。)

4 个答案:

答案 0 :(得分:3)

  

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

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

  

但是,有没有办法在函数的参数中明确预定义该限制?

不在C.您可以做的是定义一个具有固定大小数组的结构:

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

然后您可以使用arraytype *作为函数参数类型,这样您的编译器就会确保实际的函数调用使用正确类型的arraytype *指针。当然,您无法传递裸unsigned char数组,您必须使用arraytype

答案 1 :(得分:2)

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

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

  

表达式中出现的类型为array-of-T的左值衰减(带有   三个例外)成为指向其第一个元素的指针;的类型   结果指针是指向T的指针。

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

答案 2 :(得分:1)

在C中,N个事物的数组是N个事物的连续存储块。根据设计,它并不比那更复杂。因此,如果s指向1024个字符数组的开头,那么它也指向1023个数组或256个事物或3个事物的数组的开头。而s+1s+400s+768(或&s[1]&s[400]&s[768]等等也是指向的开头256件事的数组。

无论如何,编译器不太可能为你检查这些东西,尽管它可能会。

如果你想讨论一个只有256个字符的对象,而不是更多而不是更少,请将它包装成一个结构:

struct TwoFiveSix {
  char s[256];
};

如果你的函数的原型说它需要struct TwoFiveSix的地址,那么如果你尝试将其他东西传递给它,编译器肯定会抱怨。像一个字符串。

答案 3 :(得分: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惯用法通常由宏使用,以确保它们在if - else子句中作为单行语句正常工作。

这个问题是如果缓冲区不是本地缓冲区,则需要直接调用实现,如:

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]) { ... }

进行验证