c语言装逼的代码(抠一抠C语言的一些细节)

C语言是现在大部分流行语言的源起,也是编写系统软件的不二之选,C语言的一些细节值得深入探究,我来为大家讲解一下关于c语言装逼的代码?跟着小编一起来看一看吧!

c语言装逼的代码(抠一抠C语言的一些细节)

c语言装逼的代码

C语言是现在大部分流行语言的源起,也是编写系统软件的不二之选,C语言的一些细节值得深入探究。

1 关于赋值运算符(普通变量和指针变量的赋值)

先看C语言代码和对应的汇编代码

7: int a = 5; 00401048 mov dword ptr [ebp-4],5 8: int* b = &a; 0040104F lea eax,[ebp-4]

int a = 5; 汇编指令是move,表示将5的二进制序列传送到a所对应的内存空间。

可以理解为int a ← 5,将值5赋给a。

再看指针变量的赋值:

int* b = &a;

汇编指令是lea,是Load effective address的缩写——取有效地址,也就是取偏移地址。

可以理解为 b → a,b指向a。

用结构体做单链表的结点时,这样理解更容易理解链表指针的移动:

struct pNode* p,p2; p = p->next;//p指向p的下一个节点空间 p2 = p2->next->next; //p2指向p2的下一个的下一个节点空间

2 赋值与赋初值在效率上的一点差异

二者的区别在于:为变量赋值是通过赋值表达式在运行期间动态赋值,而为变量赋初值则是在定义变量的同时在编译时静态赋值。如对a进行赋值,对b进行赋初值,形式如下。

int a,b=3; a=2;

为变量赋值占用的是运行时间,而为变量赋初值占用的是编译时间。

从上面的分析得知,变量不是一定要初始化的,也可以先进行定义,再进行赋值,这和初始化的效果是一样的。但是如果想提高运行效率,就得对变量进行初始化。

3 const的一点细节

编译器通常不为普通const只读变量分配存储空间,而是将它们保存在符号表中,这使它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也更高。

4 逗号作为运算符和分隔符

逗号在C语言中有时可以作为运算符來连接表达式,有时还可以作为分隔符,起到分隔的作用。那么,该如何区分逗号是运算符还是分隔符呢?

“,”作为分隔符主要用于以下情况:

(1) 变量声明时,使用逗号分隔多个变量名。

(2) 函数有多个参数时,用逗号分隔参数。

逗号运算符是C语言提供的一种特殊的运算符,用它可以将两个表达式连接起来。例如,“1 2,4 5”,称为逗号表达式,也称为“顺序求值运算符”。它的表达式一般形式为“表达式1,表达式2”,执行顺序是先计算表达式1的值,再计算表达式2的值。表达式也可以扩展为“表达式1,表达式2,表达式3,…,表达式n”。

c=(a=3,2*a);

是将一个逗号表达式的值赋给变量c,第一个表达式a=3,第二个表达式2*a,计算得到6,因此变量c的值是6。

代码d=a=b=3,2*a;整个是一个逗号表达式,这里逗号表达式的值同样是2*a的值,结果是6。但是变量d的值是在第一个表达式中计算得到的,得到值为3。

在使用逗号运算符的时候,要注意它的优先级和结合顺序。逗号运算符优先级最低,丼且是自左至右结合的。

5 自增运算的不同写法在效率上的一点区别

x = x 1,x = 1,x ,这三个表达式哪个执行效率最高?

第一个表达式x=x 1的执行过程是先读取等号右边的x的地址,计算x 1的值,然后读取等号左边的x的地址,最后将等号右边的值传给等号左边的值。

第二个表达式x =1的执行过程是先读取等号右边的x的地址,然后计算x 1的值,最后将得到的值传给左边的x,因为x的地址已在前面读出,故省去了传值过程;

第三个表达式的执行过程是先读取x的地址,然后x自增1;

因此,x 的效率最高。

编译器优化后汇编代码应该是一样的。

从汇编来看前自增与后自增的区别:

7: a=c ; 004016AF mov eax,dword ptr [ebp-0Ch] 004016B2 mov dword ptr [ebp-4],eax 004016B5 mov ecx,dword ptr [ebp-0Ch] 004016B8 add ecx,1 004016BB mov dword ptr [ebp-0Ch],ecx 8: b= c; 004016BE mov edx,dword ptr [ebp-0Ch] 004016C1 add edx,1 004016C4 mov dword ptr [ebp-0Ch],edx 004016C7 mov eax,dword ptr [ebp-0Ch] 004016CA mov dword ptr [ebp-8],eax

6 switch语句效率入口与出口

switch相对于if…else if,具有较高的运行效率。因为switch会在编译期建立一个跳转列表,运行时可以根据跳转列表进行直接跳转。

在switch语句中,当找到与swith表达式相等的case时,执行case下的语句。case下的所有语句都执行完成后,如果一直没有break,那么程序将会执行到下一个case,而不管它的值是否与switch表达式相等,即多个case之间不具有天然的互斥性。要想使程序执行完一个case后的语句,而不进入下一个case,必须使用break语句,使程序退出switch结构。这样,后面的case也就不执行了。

C语言一个分支的结束是依赖break完成的。case只决定—序到哪里执行,而不决定到哪里结束。结束位置由break来决定,没有break就一直执行到switch完整结构结束。

所以,case是swithc语句的入口(特殊情况下也可以是default),而由break提供出口(特殊情况下是最后一条case语句的结束块符号“}”或return。

7 联合体变量赋初值

由于联合体变量具有所有成员共享一个内存地址的特点,因此为联合体变量赋初值时只能给该变量的第一个成员赋初值,其他成员不能赋初值。例如:

union number { int i; char c; float f; }m={2};

8 数组名

数组名是一指针常量,所以不能被再次赋值。只能对其数据元素逐一操作。

数组名做函数参数时退化为指针,在函数体内不能得到其长度。

二维数组名并不能赋给一个二次指针,只能赋给一个数组指针,或通过强制类型转换,赋给一个一次指针:

int arr[5][5] = {1,2,3,4,5,6,7,8}; int (*pa)[5] = arr; int *p = (int*)arr; cout<<*pa[1] 2<<endl; // 8 cout<<*(p 7)<<endl; // 8

指针变量声明并指向目标地址时,由类型信息决定目标内存空间的字节长度,当其指向一个n维数组时,其长度信息为一个n-1维数组的字节长度,所以n维数组指针声明时需要显式指定除第一维以外的其它长度信息。

指针数组名在语法层面等价于一个二级指针。

9 内在管理函数及库中一些算法的参数和返回值的void类型

malloc、sort等函数的参数和返回值都使用void类型。原因是C是一门强类型语言,又没有类型模板机制来做泛型表示。

void指针只能单纯表示地址信息,其附加的类型信息不存在,所以其为一个不完全类型,只能用于声明和传址,当需要解引用或做指针算术运算时,其类型信息附加的字节长度信息不可或缺,所以需有具体类型的强制转换。

-End-

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页