注:本文讨论的“C语言”为GNU C,而非ANSI C

标准库

语法

switch语句中的case关键词可以放在任何地方

switch (a) {
    case 1:;
      if (b==2) {
        case 2:;
      }
      else case 3: {
        for (b=0;b<10;b++) {
          case 5:;
        }
      }
      break;
    case 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类型数组的指针 */
void (*signal(int signum, void(*handler)(int)))(int);
/* (*signal(int signum, void(*handler)(int)))(int)是void类型的,因此
 * signal是一个接收两个参数,返回一个接收一个参数且返回空类型的函数指针 */

这非常有用。

指定初始化

在c99之前,你只能按顺序初始化一个结构体。在c99中可以这样做:

struct Foo {
    int x;
    int y;
    int z;
};
Foo foo = {.z = 3, .x = 5};

这段代码首先初始化了foo.z,然后初始化了foo.x. foo.y 没有被初始化,所以被置为0。

这一语法同样可以被用在数组中。以下三行代码是等价的:

int a[5] = {[1] = 2, [4] = 5};
int a[] = {[1] = 2, [4] = 5};
int a[5] = {0, 2, 0, 0, 5};

条件运算符的用法

通常我们都这样使用它:

x = (y < 0) ? 10 : 20;

但是同样也可以这样用:

(y < 0 ? x : y) = 20;

这是因为,GNU C扩展了条件运算符,使之可以返回左值。

将结构体初始化为0

struct mystruct a = {0};

这将把结构体中全部元素初始化为0。

预处理器与编译器是分开的

你可以在奇怪的地方使用#include:

printf
#include "fragment.c"        

且fragment.c 包含:

("dayum!\n");

这完全没有问题。只要#include 包含完整可解析的C表达式,预处理器并不在意它放在什么位置。

这也是为什么宏错误较难调试。

在switch 中使用范围(gcc扩展语法)

switch(c) {
  case 'A' ... 'Z': 
//do something
  break;
  case 1 ... 5 : 
//do something
}

使用前缀ob 来限定常数,使其被当做二进制数(gcc扩展语法)

printf("%d", 0b1101); 
// prints 13
posted on 2016-02-11 17:32  yanhh  阅读(328)  评论(0编辑  收藏  举报