译注:本文摘编自 Quora 的一个热门问答贴。 请在linux系统下测试本文中出现的代码
Andrew Weimholt 的回复:
switch
语句中的case
关键词可以放在if-else
或者是循环当中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
switch
(a)
{
case
1:;
// ...
if
(b==2)
{
case
2:;
// ...
}
else
case
3:
{
// ...
for
(b=0;b<10;b++)
{
case
5:;
// ...
}
}
break
;
case
4:
|
Brian Bi 的回复:
1. 声明紧随用途之后
理解声明有一条很简单的法则,不过不是什么“从左向右”这种没道理却到处宣传的法则。这一法则的观点是,一个声明是要告诉你,你所声明的对象要如何使用。例如:
1
2
3
4
|
int
*p;
/* *p是int类型的, 因此p是指向int类型的指针 */
int
a[5];
/* a[0], ..., a[4] 是int类型的, 因此a是int类型的数组 */
int
*ap[5];
/* *ap[0], .., *ap[4] 是int类型的, 因此ap是包含指向int类型指针的指针数组 */
int
(*pa)[5];
/* (*pa)[0], ..., (*pa)[4] 是int类型的, 因此pa是指向一个int类型数组的指针 */
|
更多详情请看这里: Brian Bi’s answer to C (programming language): Why doesn’t C use better notation for pointers?
2. 指定初始化:
在C99之前,你只能按顺序初始化一个结构体。在C99中你可以这样做:
1
2
3
4
5
6
|
struct
Foo {
int
x;
int
y;
int
z;
};
Foo foo = {.z = 3, .x = 5};
|
这段代码首先初始化了foo.z
,然后初始化了foo.x
. foo.y
没有被初始化,所以被置为0。
这一语法同样可以被用在数组中。以下三行代码是等价的:
1
2
3
|
int
a[5] = {[1] = 2, [4] = 5};
int
a[] = {[1] = 2, [4] = 5};
int
a[5] = {0, 2, 0, 0, 5};
|
3. 受限指针(C99):
restrict
关键词是一个限定词,可以被用在指针上。它向编译器保证,在这个指针的生命周期内,任何通过该指针访问的内存,都只能被这个指针改变。比如,在
1
2
3
4
5
6
|
int
f(
const
int
* restrict x,
int
* y) {
(*y)++;
int
z = *x;
(*y)--;
return
z;
}
|
编译器可能会假设,x
和y
所指的并不是同一个int
对象,因为如果它们指向了同一个对象,则x
的值将可以通过y
修改,这正是你保证不会发生的。因此,将允许编译器来优化f
,就好像函数原本被写做如下这样:
1
2
3
|
int
f(
const
int
* restrict x,
int
* y) {
return
*x;
}
|
如果你违反协议向f
传递两个指向同一int对象的指针时,将产生未定义行为。
我猜想,引入这一特性最初的动机之一是想让C语言在数值计算时可以Fortran一样快。在Fortran 中,默认假定数组不会重叠,因此只有你通过restrict
限定词来显式的告诉编译器数组不能重叠,编译器才能在C语言中进行这样的优化。
4. 静态数组索引(C99)
在
<