2013-10-29 56 views
1

当创建预期输入C函数,我倾向于做这样的:有没有办法预先定义C函数参数的预期长度?

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

现在,我有一个项目我编码,其中这样的功能期待的正是256的无符号的特定bytelen功能字符。

所以,我想这似乎工作如下:

function(unsigned char bytes[256]) { … 

然而,测试一个(使用GCC),它不会在编译的时候,当我经过1024个无符号字符的功能失效。将printf添加到该函数中,它甚至可以毫无问题地打印这些1024个无符号字符。

这不是我所期望的或意图的,因为 - 最终 - 功能表现得好像我会用function(unsigned char *bytes) { …

当然,我可以进行通常的健全性检查,看看是否通过了期望的长度,如果输入不完全是256个字符,程序性失败。但是没有一种方法可以在函数的参数中明确地预定义该限制吗? (还是我做错了。如果,我将不胜感激,我错在何处抬头?)

+2

可以传递具有'无符号字符字节[256]'字段的结构的地址。 – chux

回答

3

那不是我预期的或希望的,因为 - 最后 - 函数的行为就像我会使用函数(无符号字符*字节){...

您的评论是绝对正确的。在函数参数列表中写入unsigned char bytes[1024]完全相同在C中为unsigned char *bytes。它的工作原理和行为方式完全相同。

但是没有一种方法可以在函数的参数中显式地预定义极限吗?

不在C.你可以做的就是定义一个struct其中具有固定大小的数组:

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

,然后你可以使用arraytype *为你的函数参数类型,这样你的编译器,然后让它确定实际的函数调用使用正确类型的指针arraytype *。当然,你然后不能通过一个纯粹的unsigned char阵列,你必须使用arraytype

+1

“,然后你可以使用arraytype *作为你的函数参数类型”如果你打算这样做,你可能有参数是'无符号字符(* foo)[1024]',而不用去定义一个新类型。 – newacct

2

数组衰变为指针的函数,将数组大小,以及这样的:

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

型阵列的-T的左值出现在表达衰减(与 三个例外)到一个指针到它的第一元件; 结果指针的类型是指向T的指针。

(唯一的例外是当阵列是的sizeof或&运营商的操作数,或者是一个字符数组一个字符串初始化。)

+1

这不是关于*数组衰减到指针*语义,尽管它是密切相关的。更确切地说,**仅在参数列表**中,对于任何类型T和恒定正整数N,将声明T a [],T a [N]和T * a定义为相同,也就是说,它们都意味着'T * a'。 –

+2

OP:IOW,当编译器在函数参数列表(仅在那里)看到'unsigned char bytes [256]'时,它静静地将其同样视为'unsigned char * bytes'。这实际上是添加到C故意让它更“直观”: -/ –

1

在C中,N个东西的数组是N个东西的连续存储块。这并不比设计更复杂。因此,如果s指向1024个字符的数组的开头,那么它也指向1023个事物的数组的开始,或者256个事物或3个事物。并且s+1,s+400s+768(或者&s[1],&s[400]&s[768],它们是精确等价的)也指向256个数组的开始。

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

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

struct TwoFiveSix { 
    char s[256]; 
}; 

如果你的函数的原型说,它需要一个struct TwoFiveSix的地址,编译器肯定会抱怨,如果你试图通过它别的东西。就像一个字符串。

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-delimited,那么无论如何你可能需要一个运行时间strlen()验证。

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

相关问题