关于C语言的一些总结
最近看了一些书籍,总结一下程序员容易忽略的编程细节吧,对面试还是考试有帮助的,不断更新中。
1. sizeof
想必大家都知道这个关键字吧,不是函数哦,凡是在c\c++编辑器了有和其它关键字有相同颜色的单词都是关键字,这是一个计算类型或者变量在内存中的占位大小,当是类型时如sizeof(int),就是int类型占内存的大小是4字节,这里要加括号哦,接着如果是变量,如果有int a = 1, 那么你也可以不用括号, 比如 sizeof a,注意中间有空格总结一下,跟在sizeof后面的是类型时一定要括号,还有是多个操作数时表达式时也要加,当是一个变量时就可以不加。但是为了少犯错误,一般都加上吧,绝对错不了。
好,接着来说一些大家少知道的吧,前面有说的表达式时,不知道大家有没有试过,比如有
int a = 1; int b = 1; a = sizeof(b = a + 1); printf("%d %d\n", a, b);
结果是4 1;
不会吧,这是为什么啊,b不是赋值了吗?呵呵,其实这很简单,就是sizeof的属性,对于表达式是不用求值的,只要知道其类型就知道其所占空间多少了,所以表达式里就可以不用算了,如果sizeof后面是数组名,那就是数组的占内存的大小。
2.register
寄存器变量,有时为了加快程序的执行速度,定义寄存器变量是个方法,但是可能有时候情况和你没这么做效果是一样的,当没有多余的寄存器让你用了,编译器就会忽略这个声名,只当它是普通变量如:register a = 1;声名变量a是寄存器变量。
这个大家都懂,可这有什么问题么?有,寄存器变量是存在寄存器里的对不?对,那又有什么问题呢?问题大了,比如说如果我要声名一个static变量呢?我又想加快运行速度,那就来吧,static register a;这行么?很遗憾,编译报错,这是因为存储的位置不能是一个变量分身两个不同地址吧,static变量是存储在数据段里面的,register变量是存储在寄存器里面的,寄存器是位于cpu附近的,就像eax这样,既然这样,那么好像很多问题都涌发而来了,是关于sizeof和static的,看下面吧
3.static
我之前有两篇自己总结的结构体占内存和字节对齐的文章,讲得也很少,不过够用行,但是还没说明也许细节,在这里讲了算了,懒得回去改了(虽然之前那两篇改了好几次)
当我声名一个结构体变量时,注意这是在c++环境中,如果在gcc编译器里是会报错的,如下
struct
{
int a;
static int b;
}c;
sizeof(c) = 4;
咦?那b占的内存哪里去了,呵呵上面register的时候就说过了,static变量是放在数据段里面的,和其它变量是区分开的,所以无论你是定义全局的struct还是局部的,都是不占用struct变量的内存,这是在c++环境中的,得用g++编译器,但是有个问题没解决,就是怎么使用b 啊, c.a可以,但是c.b就报错了,其实我也不知道怎么使用,求大神解释。网上看了一些文章,网友们说这意义不大,一般没人会这么定义的,而是直接定义static struct,这样他的成员都是static,不知道对不对,以后再考证。
4.为什么数组不设边界检测呢?像字符串数组一样,以'\0'来结束多好
呵呵,对啊,但是它就不那么做,原因是为了
1.提高编译器的速度,减轻编译器的负担
2.可以提高指针的灵活性,当一个指针指向数组时,指针就相当于数组来使用了,如果带有边界检测,那么信息存在哪里呢?数组头?那指针怎么存?像字符数组那样在最后面加个0识别?拜托,那整形怎么办?你想太多了,在实现上没必要考虑那么多,只要能用就行了,
3.当初c编译器就是没有带检测的,现在也没有,所以这就只增加程序员的负担而已,机器是蛮爽的。呵呵!!
大家有问题的可以说,讨论讨论,这也是我在网上看别人的总结来的。
5.数组越界问题
看下面代码,都是对一个数组初始化过程
1.
#define LEN 5
int a[LEN]; int *p = NULL; for (p = &a[LEN]; p > &a[0];) *--p = 0;
2.
#define LEN 5
int a[LEN]; int *p = NULL;
for (p = &a[LEN-1]; p >= &a[0]; p--) *p = 0;
看了上面两个代码有什么问题吗?其实只有代码2有问题。因为c标准中,允许指向同一个数组的针像比较运算,但是只允许数组最后一个元素地址和其后一个越界地址比较,而没有说明可以开始的第一个元素地址和数组前一个地址比较。大多数编译器也许可以运行没出错,但是在移植代码过程中,如果出错就很难想象后果了,c标准有机会的话还是要看下的,不然都不知道竟然还有这种规定。