语句
c语言的语句通过编译器生成代码,使得程序可以执行
语句的组成
以分号结束,由 运算符, 表达式, 关键字组成
运算符
sizeof 返回类型是size_t
%模运算 得出结果永远小于模数
语句的分类
赋值语句:语句中有= 数据对象: 数据所占用的空间
左值右值,=左边的数据( 代表的意义是可以被修改的值)
右值,表达式等, 一般代表不可修改的值左值放在右值使用的时候使用的不是右值本身,而是右值中的数值。
代码举例
#define BASE 20
int main()
{
int i_num = 0; //初始化语句
i_num = 100; // 赋值语句
int sum = i_num; // 赋值语句
sum = 100 + 200; // 右值表达式
sum + i_num + sum; // 右值表达式
sum = BASE * 2;
int i_other_num = sum = i_num = BASE; //连续赋值
return 0;
}
反汇编
#define BASE 20
int main()
{
00171650 push ebp
00171651 mov ebp,esp
00171653 sub esp,0E4h
00171659 push ebx
0017165A push esi
0017165B push edi
0017165C lea edi,[ebp-0E4h]
00171662 mov ecx,39h
00171667 mov eax,0CCCCCCCCh
0017166C rep stos dword ptr es:[edi]
每一次进入一个函数的时候,将栈顶备份,将当前函数的栈顶和栈底指针分在同一个,产生了新栈。分配了空间,再将需要备份的寄存器压进栈,将栈里的空间全部赋值为0CCCCCCCCh ,此时当前函数当中的所有局部临时变量的地址分配完成。
int i_num = 0; //初始化语句
0017166E mov dword ptr [i_num],0
i_num = 100; // 赋值语句
00171675 mov dword ptr [i_num],64h
int sum = i_num; // 赋值语句 把左值当成右值使用
0017167C mov eax,dword ptr [i_num] 第一步,转换成数值,放在eax寄存器里
0017167F mov dword ptr [sum],eax 第二步 , 实际赋值还是不可修改的。
sum = 100 + 200; // 右值表达式
00171682 mov dword ptr [sum],12Ch 先计算,再赋值
sum + i_num + sum; // 右值表达式
sum = BASE * 2;
00171689 mov dword ptr [sum],28h
int i_other_num = sum = i_num = BASE; //连续赋值 从右到左连续赋值
00171690 mov dword ptr [i_num],14h 按照优先级分成一个个表达式
00171697 mov eax,dword ptr [i_num]
0017169A mov dword ptr [sum],eax
0017169D mov ecx,dword ptr [sum]
001716A0 mov dword ptr [i_other_num],ecx
return 0;
001716A3 xor eax,eax
}
002016B7 pop edi
002016B8 pop esi
002016B9 pop ebx
002016BA mov esp,ebp
002016BC pop ebp
002016BD ret
函数栈在分配空间之前会对代码进行扫描,判断生成多大的空间。使用的时候不需要对变量一一分配空间。
赋值操作使用move语句,如果是一个字面值,立即数,直接放进内存;如果是一个变量,第一步先把变量的值取出来变成立即数,再把它赋值。如果有计算,先计算出值,再赋值。如果是两个变量相加,显示生成add计算;连续赋值,一个表达式有一定的优先级放在一起,按照从右到左的顺序赋值。
运算符优先级
一般会使用二叉树来定义表达式的优先级
sum = 25 + BASE *i_num / 3;
反汇编
002016A3 imul eax,dword ptr [i_num],14h 乘法,
002016A7 cdq
002016A8 mov ecx,3
002016AD idiv eax,ecx
002016AF add eax,19h
002016B2 mov dword ptr [sum],eax
sum = 25 + BASE *(i_num / 3);
002016A3 mov eax,dword ptr [i_num]
002016A6 cdq
002016A7 mov ecx,3
002016AC idiv eax,ecx
002016AE imul edx,eax,14h
002016B1 add edx,19h
002016B4 mov dword ptr [sum],edx
typedef unsigned int index; //取别名(定义含义更鲜明)区分其他的变量类型
index i = BASE;
size_t sz = sizeof(index);
printf("%d", i++); 语句执行完成后 自增
printf("%d",i );
printf("%d", ++i); 先自增
printf("%d", i);
printf("%d", i_num*i / BASE + (sum - i--)*++i); // 加括号,增加可读性
反汇编
index i = BASE;
012B17C7 mov dword ptr [i],14h
size_t sz = sizeof(index);
012B17CE mov dword ptr [sz],4 如果size_t是函数,会调用call指令跳转, 直接赋值说明了size_t是操作符
printf("%d", i++);
012B17D5 mov eax,dword ptr [i] 把i的值先存放进exa寄存器
012B17D8 mov dword ptr [ebp-100h],eax 放进临时变量
012B17DE mov ecx,dword ptr [i] 再放进ecx
012B17E1 add ecx,1 +1
012B17E4 mov dword ptr [i],ecx i已经发生了改变
012B17E7 mov edx,dword ptr [ebp-100h] 给printf传递的是未改变的临时变量
012B17ED push edx
012B17EE push offset string "%d" (012B6B30h)
012B17F3 call _printf (012B1316h)
012B17F8 add esp,8
printf("%d",i );
012B17FB mov eax,dword ptr [i]
printf("%d",i );
012B17FE push eax
012B17FF push offset string "%d" (012B6B30h)
012B1804 call _printf (012B1316h)
012B1809 add esp,8
printf("%d", ++i);
012B180C mov eax,dword ptr [i]
012B180F add eax,1
012B1812 mov dword ptr [i],eax
012B1815 mov ecx,dword ptr [i] 把i直接传递给printf
012B1818 push ecx
012B1819 push offset string "%d" (012B6B30h)
012B181E call _printf (012B1316h)
012B1823 add esp,8
printf("%d", i);
012B1826 mov eax,dword ptr [i]
012B1829 push eax
012B182A push offset string "%d" (012B6B30h)
012B182F call _printf (012B1316h)
012B1834 add esp,8
printf("%d", i_num*i / BASE + (sum - i--)*++i);
012B1837 mov eax,dword ptr [i]
012B183A add eax,1
012B183D mov dword ptr [i],eax
012B1840 mov ecx,dword ptr [sum]
012B1843 sub ecx,dword ptr [i]
012B1846 imul ecx,dword ptr [i]
012B184A mov eax,dword ptr [i_num]
012B184D imul eax,dword ptr [i]
012B1851 xor edx,edx
012B1853 mov esi,14h
012B1858 div eax,esi
012B185A add eax,ecx
012B185C mov dword ptr [ebp-100h],eax
012B1862 mov edx,dword ptr [i]
012B1865 sub edx,1
012B1868 mov dword ptr [i],edx
012B186B mov eax,dword ptr [ebp-100h]
012B1871 push eax
012B1872 push offset string "%d" (012B6B30h)
012B1877 call _printf (012B1316h)
012B187C add esp,8
size_t 定义 (传递变量类型和变量名)
#ifdef _WIN64
typedef unsigned __int64 size_t;
typedef __int64 ptrdiff_t;
typedef __int64 intptr_t;
#else
typedef unsigned int size_t;
typedef int ptrdiff_t;
typedef int intptr_t;
#endif