void foo(const char *s);
相当于:
void foo(const char s[]);
是否有类似的以下两个?
void foo(char * const s);
void foo(const char * const s);
答案 0 :(得分:14)
在C ++中,编译器会自动将类型为的N个元素的数组的函数参数(其中N
可以未知)转换为指向T 的指针。在相同的转换中,参数的顶级const
限定符将被删除:
void f( const int x ); // => declares: void f( int )
void f( int * const ); // => declares: void f( int* )
这意味着在指针的情况下,顶级const限定符被删除,而在数组的情况下,它被转换为指针。现在,另一方面,你不能混合两者,只是因为你不能声明类型为T 的N个元素的常量数组,因为数组总是const。这意味着你不能写:
void f( const int a[] const ); // Invalid type definition
由于参数的类型无效。如果它是有效类型,则转换将适用,但由于它不适用,编译器将在尝试执行转换之前拒绝该代码。
这在C ++ 03标准的§8.3.5/ 3中得到了处理(可能在C ++ 11中很接近)
单个名称可用于单个范围内的多个不同功能;这是函数重载(第13条)。具有给定参数列表的函数的所有声明应完全同意返回值的类型以及参数的数量和类型;省略号的存在与否被认为是函数类型的一部分。使用以下规则确定函数的类型。每个参数的类型由其自己的decl-specifier-seq和声明符确定。在确定每个参数的类型之后,将“T数组”或“函数返回T”类型的任何参数分别调整为“指向T的指针”或“指向函数返回T的指针”。在生成参数类型列表之后,会对这些类型进行多次转换以确定函数类型。 删除修改参数类型的任何cv-qualifier。 [示例:类型
void(*)(const int)
变为void(*)(int)
- 末端示例]此类cv限定符仅影响函数体内参数的定义;它们不会影响函数类型。如果存储类说明符修改了参数类型,则删除说明符。 [示例:register char *变为char * -end示例]此类存储类说明符仅影响函数体内参数的定义;它们不会影响功能类型。生成的已转换参数类型列表是函数的参数类型列表。
请注意,由于编译器将执行该转换,因此最好按照最少惊喜的原则编写将由编译器使用的实际类型:
void f( int a[10] ) { a[5] = 7; }
编译器不会检查传递的数组是否有10个元素,它将声明读作void f( int * )
,并且很乐意接受带有少量元素数组的调用,甚至根本没有数组(指针)到单个int)。在实际代码中使用指针:
void f( int *a ) { a[5] = 7; }
可能会在代码审查中触发一些警报:我们是否保证在f
的所有调用中,参数将至少为6个元素?我们是否也不能通过大小以防万一?
答案 1 :(得分:13)
您不能在C89中,但在C99中,您可以将等价物声明为:
void foo(char s[const]);
void foo(const char s[const]);
答案 2 :(得分:0)
这在某些情况下会很有用:
class AA {
void foo(char a[]);
void foo(const char a[]);
};
void AA::foo(char* const a) { … }
void AA::foo(const char* const a) { … }
并在C:
extern void foo(char a[]);
extern void fooc(const char a[]);
void foo(char* const a) { … }
void fooc(const char* const a) { … }
答案 3 :(得分:0)
我认为指针可以为null,而数组参数不能为null(并且允许编译器优化知道;但是在一个简单的示例中,gcc-4.6不进行这样的优化,即使使用 - O3)。
我期望编译器会对下面的两个函数进行不同的优化。它不是。我手头没有我的C标准来检查它是否可以在下面的ss中删除测试。
int s (int *t)
{
if (!t)
return 0;
return t[0] + t[1];
}
int ss (int t[])
{
if (!t) // never false, since t is an array!!
return 0;
return t[0] + t[1];
}