参数声明中的静态数组索引:一个不错且鲜为人知的C语言特性
2013-07-31 11:49
295 查看
C语言的创造者们一定都热衷于让关键字的数目尽可能的少.今天将向你展示另一个可使用C99中static关键字地方.
也许你已经看到过在数组的参数声明中包括数组的长度:
[cpp] view
plaincopyprint?
void foo(int myArray[10]);
这样的函数仍可接收整数指针int *,但是长度[10]可以对阅读代码的人们可当作文档,传达着这相函数预期一个长度为10个整数的数组的信息.
除此之外,你还可以在括号之中加上static关键字[1]:
[cpp] view
plaincopyprint?
void bar(int myArray[static 10]);
这会告诉编译器:函数会假定传进来的实参至少有10个元素.(值得注意的是这就会把NULL排除在外!)
这样做有二个目的:
1.编译器在优化代码时能够用到这些信息[2]
2.当编译一个带有上述声明的bar时,如果传递下面三种实参[3]进去, 编译器能够警告调用者:
a. 传递NULL
[cpp] view
plaincopyprint?
bar(NULL);
[html] view
plaincopyprint?
warning: null passed to a callee which requires a non-null argument [-Wnonnull]
bar(NULL);
^ ~~~~
b. 传递一个(比10)更小的数组
[cpp] view
plaincopyprint?
int a[9];
bar(a);
[html] view
plaincopyprint?
warning: array argument is too small; contains 9 elements, callee requires at least 10 [-Warray-bounds]
bar(a);
^ ~
c. 传递一个(比10)更大的数组
[cpp] view
plaincopyprint?
int b[11];
bar(b);
[html] view
plaincopyprint?
[no output]
这在当你确信函数能接收的数组的长度时很有用, 因为它既可以为阅读代码的人提供文档信息,又能让编译器帮忙捕获错误.
[1]. 也可以在括号中使用const关键字. 这会让指向myArray的指针变成指针常量.
[2].不确实编译器是否真的会优化代码, 因为寄希望于程序员们都留心编译警告信息是十分不靠谱的.
[3].使用的编译器:
原文地址:A nice, little known C feature: Static array indices in parameter declarations
看过这篇文章,但去查了C语言的参考手册<C A Reference Manual>,发现C99中在函数参数声明时,的确允许在数组的括号中加上限制符. 以下译自<C A Reference Manual> Chap 9, 9.3 FORMAL PARAMETER DECLARATION, P296
"C99扩展了声明形式参数的语句. 一个用于修饰数组的限制符列表允许出现在数组声明者的最上层[]括号中.数组限制符(类型限制符)const, volatile和restrict将数组和指针类型等同对待.也就是说,这样的参数声明:
T A[qualifier-list e]
与以下声明等价:
T *qualifier-list e
例子:
给出这些C99中的声明:
[cpp] view
plaincopyprint?
<pre name="code" class="cpp">extern int f(int x[const 10]);
extern int g(const y[10]);</pre>
<pre></pre>
那么在f函数中参数x会被看成是int * const类型(这是一个指向整型的指针常量), 而在g函数中参数y被看成它有const int *类型(也就是一个指向整型常量的指针).
译注:指向整型的指针常量,是指针的值无法改变,它指向一个可变的整型变量,也即无法改变p的值,但是*p的值是可以改的. 而后面的常量指针,是指向一个整型常量的指针,也就是p可以改变,但是*p是无法改变的.
在C99中,数组限制符static也允许出现在数组的括号之中.它对C的实现(编译器)是一个优化提示,断言实际的数组参数不能是NULL并且在进入函数体时要有所声明的类型和长度.如果没有这个限制符,NULL指针就可以当作实参作为数组传进来,就会使编译器很难知道它是安全的,比如,当在进入函数时要预取一个输入数组参数的内容时.
另外,对于原型(不能是函数定义)中的C99形式数组参数声明,其长度可以用星号(*)替代,这意味着实参将会是一个可变长数组.在原型声明中作为数组大小的任何非常量表达式与星号是等价.函数定义时必须提供一个非常量的表达式作为数组大小."
其实这里面提到的目的都是让编译器在编译时帮忙探测更多的错误.但是貌似大多数编译并不支持对函数声明数组参数的修饰,比如以上的例子在gcc中就完全没有效果,gcc不会给出任何提示.上面的建议只有static的修饰有实用意义,那就是帮忙排除NULL实参.其他的都仅有学术研究价值.
其实,在实际使用过程中,对于数组的参数,都必须同时给出另外一个参数来传达数组的长度,就像这样:
[cpp] view
plaincopyprint?
void foo(int a[], int len);
这是提倡的,也是大量普遍使用的方式.
转自:/article/2420825.html
也许你已经看到过在数组的参数声明中包括数组的长度:
[cpp] view
plaincopyprint?
void foo(int myArray[10]);
这样的函数仍可接收整数指针int *,但是长度[10]可以对阅读代码的人们可当作文档,传达着这相函数预期一个长度为10个整数的数组的信息.
除此之外,你还可以在括号之中加上static关键字[1]:
[cpp] view
plaincopyprint?
void bar(int myArray[static 10]);
这会告诉编译器:函数会假定传进来的实参至少有10个元素.(值得注意的是这就会把NULL排除在外!)
这样做有二个目的:
1.编译器在优化代码时能够用到这些信息[2]
2.当编译一个带有上述声明的bar时,如果传递下面三种实参[3]进去, 编译器能够警告调用者:
a. 传递NULL
[cpp] view
plaincopyprint?
bar(NULL);
[html] view
plaincopyprint?
warning: null passed to a callee which requires a non-null argument [-Wnonnull]
bar(NULL);
^ ~~~~
b. 传递一个(比10)更小的数组
[cpp] view
plaincopyprint?
int a[9];
bar(a);
[html] view
plaincopyprint?
warning: array argument is too small; contains 9 elements, callee requires at least 10 [-Warray-bounds]
bar(a);
^ ~
c. 传递一个(比10)更大的数组
[cpp] view
plaincopyprint?
int b[11];
bar(b);
[html] view
plaincopyprint?
[no output]
这在当你确信函数能接收的数组的长度时很有用, 因为它既可以为阅读代码的人提供文档信息,又能让编译器帮忙捕获错误.
[1]. 也可以在括号中使用const关键字. 这会让指向myArray的指针变成指针常量.
[2].不确实编译器是否真的会优化代码, 因为寄希望于程序员们都留心编译警告信息是十分不靠谱的.
[3].使用的编译器:
Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn).
原文地址:A nice, little known C feature: Static array indices in parameter declarations
看过这篇文章,但去查了C语言的参考手册<C A Reference Manual>,发现C99中在函数参数声明时,的确允许在数组的括号中加上限制符. 以下译自<C A Reference Manual> Chap 9, 9.3 FORMAL PARAMETER DECLARATION, P296
"C99扩展了声明形式参数的语句. 一个用于修饰数组的限制符列表允许出现在数组声明者的最上层[]括号中.数组限制符(类型限制符)const, volatile和restrict将数组和指针类型等同对待.也就是说,这样的参数声明:
T A[qualifier-list e]
与以下声明等价:
T *qualifier-list e
例子:
给出这些C99中的声明:
[cpp] view
plaincopyprint?
<pre name="code" class="cpp">extern int f(int x[const 10]);
extern int g(const y[10]);</pre>
<pre></pre>
那么在f函数中参数x会被看成是int * const类型(这是一个指向整型的指针常量), 而在g函数中参数y被看成它有const int *类型(也就是一个指向整型常量的指针).
译注:指向整型的指针常量,是指针的值无法改变,它指向一个可变的整型变量,也即无法改变p的值,但是*p的值是可以改的. 而后面的常量指针,是指向一个整型常量的指针,也就是p可以改变,但是*p是无法改变的.
在C99中,数组限制符static也允许出现在数组的括号之中.它对C的实现(编译器)是一个优化提示,断言实际的数组参数不能是NULL并且在进入函数体时要有所声明的类型和长度.如果没有这个限制符,NULL指针就可以当作实参作为数组传进来,就会使编译器很难知道它是安全的,比如,当在进入函数时要预取一个输入数组参数的内容时.
另外,对于原型(不能是函数定义)中的C99形式数组参数声明,其长度可以用星号(*)替代,这意味着实参将会是一个可变长数组.在原型声明中作为数组大小的任何非常量表达式与星号是等价.函数定义时必须提供一个非常量的表达式作为数组大小."
其实这里面提到的目的都是让编译器在编译时帮忙探测更多的错误.但是貌似大多数编译并不支持对函数声明数组参数的修饰,比如以上的例子在gcc中就完全没有效果,gcc不会给出任何提示.上面的建议只有static的修饰有实用意义,那就是帮忙排除NULL实参.其他的都仅有学术研究价值.
其实,在实际使用过程中,对于数组的参数,都必须同时给出另外一个参数来传达数组的长度,就像这样:
[cpp] view
plaincopyprint?
void foo(int a[], int len);
这是提倡的,也是大量普遍使用的方式.
转自:/article/2420825.html
相关文章推荐
- 参数声明中的静态数组索引:一个不错且鲜为人知的C语言特性
- 声明一个指向含有10个元素的数组的指针,其中每个元素是一个函数指针,该函数的返回值是int,参数是int*,正确的是()
- C语言中,即使参数声明为数组,它仍然是个指针
- 黑马程序员--01.JDK5部分新特性--01【静态导入】【可变参数数组】【享元设计模式的思想】
- 深入理解C语言特性-指针 数组 声明
- C语言多维数组的声明,引用。---当数组索引值超出数组元素个数会怎么样?
- 黑马程序员---集合框架工具类Collections,数组工具类Arrays常见方法以及1.5版本新特性(高级for,可变参数和静态导入)
- 对个帖子的总结:严重声明:C语言中不存在数组的类型!它仅仅是一个概念!
- C语言下的创建一个数组, 实现函数init()初始化数组、 实现empty()清空数组、 实现reverse()函数完成数组元素的逆置。 要求:自己设计函数的参数,返回值。
- c语言中函数的嵌套调用(关于函数声明的一个例子)
- lucene创建索引高级特性和索引创建参数优化
- C语言 写一个函数,将一维数组中的元素逆序存放
- 1.5新特性静态导入、增强for、可变参数、自动装箱拆箱、枚举
- Java5新特性之静态导入、可变参数、增强for循环、自动拆装箱
- C语言数组名作为函数参数
- C语言下数组做参数的退回问题探讨
- 一个比较简单的生成value - key静态字符数组的方法
- 黑马程序员------集合(No.2)(Collections、Arrays、集合与数组转换、高级for、可变参数、静态导入)
- C语言--数组作为参数
- C语言 内存分配 地址 指针 数组 参数 实例解析