Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1204463
  • 博文数量: 185
  • 博客积分: 495
  • 博客等级: 下士
  • 技术积分: 1418
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-02 15:12
个人简介

治肾虚不含糖,专注内核性能优化二十年。 https://github.com/KnightKu

文章分类

全部博文(185)

文章存档

2019年(1)

2018年(12)

2017年(5)

2016年(23)

2015年(1)

2014年(22)

2013年(82)

2012年(39)

分类:

2012-10-10 09:14:12

原文地址:以C99的眼光重温C语言 作者:rocksword

在开始以前请先阅读以下条款

    1.这里不要将C和C++混为一谈了,这两个语言的制定都有自己独立的标准委员会。
    2.并不是所有的编译器都支持C99,试验所使用的gcc也不是完全支持C99。
    3.不要以讹传讹,想要知道结果,与其将信将疑的听别人讲,不如自己动手试下。
    4.代码中的一些细节之处不要忽略。
    5.本文所有内容都经过了仔细揣摩实践,但本人才疏学浅,难免有错误之处,若您发现,请跟帖或是邮件指出,谢谢。

备注
    代码都在win xp sp2 & mingw32 & 3.4.2下通过。
    编译指令:gcc -std=c99 source.c -o desc
    作者:harite
    邮箱:Harite.K(at)gmail.com
    引自:http://hi.baidu.com/harite/blog/item/73aac9ceb96b6a0292457e8a.html

1.灵活数组域

struct name
{
int namelen;
char namestr[1];
};

型如这样的结构体,利用一些内存分配技巧可以使namestr数组用起来好像有多个元素。这在以前是被标准称为“没有遵守要求”的代码,虽然他们在很多实现上都工作正常(偶尔有数组越界警告)。而在C99中,添加了“灵活数组域”概念,允许结构的最后一个域省略数组大小。
struct name
{
int namelen;
char namestr[];
};

2.指定初始值
对于一个拥有很多域的结构体

struct moreelement
{
int a;
int b;
int c;
};

来说,如果我只想初始化它的几个域,则可以这样:
struct moreelement mystruct = {.a=10,. c=40};
printf("%d,%d,%d\n", test.a,test.b,test.c);
--
10,0,40

另外要说的是,同样的方式也适合union
typedef union
{
     int a;
     char b;
}myunion;
myunion tu = {.b='A'};
printf("%d,%c\n", tu.a,tu.b);

--
65,A

3.
复合常量
有型如下面的函数

struct people
{
int length;
int weight;
int age;
};

void makepeople(struct people want);
你想给它传递一个常数,则使用如下语法调用
makepeople((struct people){1.6, 0.5, 20});
当然你也可以使用“指定初始值”功能这样调用
makepeople((struct people){.length=1.6, .age=20});

4.不具有移植性的做法
交换两个整型变量的值,高手会这样写:

int a = 20;
int b = 30;
a ^= b ^= a ^= b;

其实它不具有可移植性,因为它试图在序列点之间两次修改变量 a, 而这是无定义的。

§ 什么是序列点?
§ 序列点是一个时间点(在整个表达式全部计算完毕之后或在 ||、 &&、 ? : 或逗号 运算符处, 或在函数调用之前), 此刻尘埃落定, 所有的副作用都已确保结束。
§ ANSI/ISO C 标准这样描述: 在上一个和下一个序列点之间, 一个对象所保存的值至多只能被表达式的 计算修改一次。而且前一个值只能用于决定将要保存的值。
§ 对于ansi/iso c标准的理解:
§ 它说在一个表达式中如果某个对象需要写入, 则在同一表达式中对该对象的访问应该只局限于直接用于计算将要 写入的值。这条规则有效地限制了只有能确保在修改之前才访问 变量的表达式为合法。例如 i = i+1 合法, 而 a[i] = i++ 则非法。


为了让其具有可移植性,可以这样写:
int a = 20;
int b = 30;
a ^= b;
b ^= a;
a ^= b;


5.数组的指定初始值
有时你可能会需要指定一些数组元素的初值,C99提供了这一功能。
int array[10] = {[0] = 0, [2] = 4, [8] = 8};
这个可以和结构的指定初始值一起用,但要注意语法:
struct mystruct
{
int a[10];
int b;
int c;
} own[] = {[0].a[3] = 0, [1].c = 20};

§注意:
§以上这段代码生成了2个mystruct结构体,并且初始化第一个结构体变量中的域中的a数组中的索引值为3的那个元素的值为0,初始化第二个结构体变量中的域中的整数c值为20。(比较生疏,可见这些新特性暂时不为人们所常用:-),当然,也可能我们的见识短。)

6.新加的宏定义和可变参宏
添加的宏定义"__func__"(小写)以及为支持可变参数宏而定义的"__VA_ARGS__"(大写)的使用(这在调试&日志记录中特别有 用),另外,使用#,##“粘贴符号”时,如果参数为空,会扩展成空串而不会出错,这个放开也有其负面影响--一些调用语法会通过编译,从而造成意想不到 的副作用(下面程序有体现)。追加的一点:可变参宏的变元也可以是变元。
#include

#define DEBUG_LOGS(fmt, ...) \
                             fprintf(stdout, "<时间:%s %s文件名:%s|当前函数体:%s|行数:%d>\n调试内容:\n[\n" fmt "\n]\n\n", \
                             __TIME__,__DATE__,__FILE__, __func__, __LINE__, ##__VA_ARGS__ );
/*这里加入;号也可以编译通过,不过强烈建议不要加!*/

/*可变参宏定义的参数变元也可以是变元,就是说:可变参宏可以签套*/
#define DEBUG(debug_name, ...) \
                             debug_name(__VA_ARGS__)


int main()
{
DEBUG_LOGS("array=%d", 20);

/*fmt参数只能是常量,不能是变量,如下方式无法通过编译
char fmt[] = "array=%d";
DEBUG_LOGS(fmt, 20);
*/

DEBUG_LOGS("array=%d,%d,%d,%d", 20, 30, 40,50);

/*
以下3种使用方式可以通过编译,但是他们是
错误的使用方式,应该绝对避免!
*/

DEBUG_LOGS("array=%d");/*仍能通过编译,这里会输出上一次输出结果的第一位:20,当然,不同平台可能有差异(未验证)*/
DEBUG_LOGS("array=%d,%d");//同上,将输出20,30
DEBUG_LOGS("array=%d,%s,%ld");//可以通过编译,但是程序会异常,不过仍能正常结束(奇怪)。
/*
如果在宏DEBUG_LOGS的定义中不使用##,则以上3种调用都无法通过编译(坏##,呵呵)。
*/

/*可变参宏定义的参数变元也可以是变元,注意理解它的扩展过程*/
DEBUG(DEBUG_LOGS, "array=%d,%d", 80, 90);

return 0;
}

可见,C99中的宏功能被大大加强了!

7.对于负数的/和%操作看法的误区
之前有人说C99标准里更改了负数的/和%操作的意义,
以至于以下表达式才通过:
assert(-22 / 7 == -4);
assert(-22 % 7 == 6);

而以下表达式是不通过的:
assert(-22 / 7 == -3);
assert(-22 % 7 == -1);

其实这种看法是错误的
C99中对于这块儿的规定如下:
“6 When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a
可见,刚才那两种结果都符合C99要求,并且C99并没有对这一运算的结果做其他说明,这个结果完全是交给编译器制作者的,但是结果必须符合那个式子!
在现实中,不论是本试验所用的编译器还是vc6或是vc2005所带的c编译器都会以以下表达式为准:
assert(-22 / 7 == -3);
assert(-22 % 7 == -1);
这一结果恐怕是绝对的定局,不会改变。


(--未完待续--最后更新日期:2007-05-16-19:07--)

----其他相关资源----

用 C99 进行开放源代码的开发 - by IBM


转自:http://hi.baidu.com/harite/blog/item/73aac9ceb96b6a0292457e8a.html

阅读(820) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~