|
俺用C的时间比用C++长多了,现在C++的代码中,也不经意的会透露出一些C的风格。记得有位高人说过:好的C代码一般都不是好的C++代码。所以我的C++代码看起来并不是很舒服。
大家学编程语言应该有一大部分人看过潭浩强的C语言的书吧,那本书写得很好,但是却写得很片面,没有让人了解到C的一些更efficient的特性。下面来讲一些:
大家是不是经常碰到这种情况,有一个指针,指向一个数组,然后把这个指针传给一个函数处理,那么这个函数在处理这个指针的时候,怎么能知道数组的元素呢?比如说,你传一个坐标指针给一个函数,这个函数如何知道这个指针会有两个元素(x,y)呢?
一般的写法是:
char buf[255];
char *p = buf;
(void)process_buf(p);
这里process_buf的定义是void process_buf(char *p);
无论你定义成void process_buf(char newbuf[]);
或者是void process_buf(char newbuf[255]);
实际上传进来的就是一个指针,你可以任意操作。
但是你的函数这个时候就不好办了,不知道这个指针究竟能操作到什么地方。
或者传进来的是个垃圾指针,函数都不知道。
所以在C99标准里面,比较efficient的声明process_buf是:
void process_buf(char newbuf[static 255]);
(不要用VC去试,那个不支持C99,GCC对C99支持得最好,可以用-std=c99编译选项)
这个声明的意思就是保证newbuf这个指针最少有255个元素。
==============================================
另外,是否经常碰到这种情况,有一个函数叫calXY(pos_t *xy);
pos_t的定义位:
typedef struct {int x; int y;} pos_t;
然后你已经计算出x和y的值了,但是为了传给calXY函数,又不得不再声明一个
pos_t pos;
pos.x = my_x;
pos.y = my_y;
之类的?其实比较好的做法是不用这样,而是直接:
calXY( (pos_t*){my_x, my_y} );
==============================================
当碰到要计算一个struct里面的某个成员的offset时,你又会怎么做呢?
比如有个结构:
struct my_struct {
int a;
int b;
};
当你想获得b在my_struct这个结构中的offset的时候,你会怎么做呢?是不是
struct my_struct test;
int offset = &(test.b) - &test; 呢?
这里告诉你个更efficient的做法:
struct my_struct *p;
p = 0;
int offset = &(p->b); 都不需要给p分配内存就可以做到。
==============================================
还有,在编写网络传输的时候,大家是不是碰到过这种情况呢?
要把某人的聊天信息传输过去,那么如何来定制这个结构呢?有些比较愚蠢的办法是:
typedef struct chat_s {
struct message_header head;
char msg[255];
} chat_t;
来发聊天消息,因为他们不知道如何定制一个变长的结构体。
有些人会比较聪明,会知道用:
typedef struct chat_s {
struct message_header head;
char msg[1];
} chat_t;
这样的结构来保存聊天消息,这样可以更方便的指定变长,但是又是连续内存的结构体。
那么实际上呢,C本身就对这种结构有支持,正确的写法应该是:
typedef struct chat_s {
struct message_header head;
char msg[];
} chat_t;
当然,这个特性只有在支持C99的编译器上才能编译通过。
==============================================
还有,对于struct timeval这个结构,大家都知道吧,它里面有两个东西,一个
tv_sec和一个tv_usec,是用来设定时间的,很多时候我们都只需要tv_usec来
表示一个微秒级的时间,而tv_sec常常都是0,比如在select的时候。我们会这样写:
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 30;
select(xx, xx, xx, xx, &tv);
当然,这样写是绝对正确的,但是我们需要更efficient的写法,就是:
select(xx, xx, xx, xx, &( struct timeval ){.tv_usec = 30 });
这样默认的tv_sec会被设置为0,这是一个比较好的初始化方法,不需要memset
也不需要一个个的赋值。
这个也是C99的特性。
==============================================
总而言之,潭浩强老师的书确实写得不错,在他那个年代,C99规范还没出来的时候
他总结得很全,但是随着现在几乎所有的C编译器都开始支持C99,包括一些C++编译
器也开始支持C99规范,我们是不是也应该开始改改我们的一些编程习惯?
|
|