C语言语法入门-运算和数据类型
9unk Lv5

运算

进行加法运算的 + 和进行乘法运算的 * 等符号,称为运算符。

运算符和操作数

读取两个整数值,然后显示它们的和、差、积、商和余数。

代码清单2-1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*程序名:list0201.c*/
/*读取两个整数的值,然后显示它们的和、差、积、商和余数*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int x, y;
puts("请输入两个整数。");
printf("整数x:"); scanf("%d", &x);
printf("整数y:"); scanf("%d", &y);

printf("x + y = %d\n", x + y);
printf("x - y = %d\n", x - y);
printf("x * y = %d\n", x * y);
printf("x / y = %d\n", x / y);
printf("x %% y = %d\n", x % y);
return 0;
}

反汇编(debug模式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
00665090     push        ebp  
00665091 mov ebp,esp
00665093 sub esp,0DCh
00665099 push ebx
0066509A push esi
0066509B push edi
0066509C lea edi,[ebp-1Ch]
0066509F mov ecx,7
006650A4 mov eax,0CCCCCCCCh
006650A9 rep stos dword ptr es:[edi]
006650AB mov eax,dword ptr [__security_cookie (066A020h)]
006650B0 xor eax,ebp
006650B2 mov dword ptr [ebp-4],eax
006650B5 mov ecx,offset _FC42537F_mjc@cpp (066C008h)
006650BA call @__CheckForDebuggerJustMyCode@4 (0661307h)

//puts("请输入两个整数。");
006650BF mov esi,esp
006650C1 push offset string "\xc7\xeb\xca\xe4\xc8\xeb\xc1\xbd\xb8\xf6\xd5\xfb\xca\xfd\xa1\xa3" (0667BD8h)
006650C6 call dword ptr [__imp__puts (066B170h)]
006650CC add esp,4
006650CF cmp esi,esp
006650D1 call __RTC_CheckEsp (0661230h)

//printf("整数x:"); scanf("%d", &x);
006650D6 push offset string "\xd5\xfb\xca\xfdx\xa3\xba" (0667B30h)
006650DB call _printf (06613ACh)
006650E0 add esp,4
006650E3 lea eax,[x]
006650E6 push eax
006650E7 push offset string "%d" (0667B38h)
006650EC call _scanf (06613A2h)
006650F1 add esp,8

//printf("整数y:"); scanf("%d", &y);
006650F4 push offset string "\xd5\xfb\xca\xfdy\xa3\xba" (0667BECh)
006650F9 call _printf (06613ACh)
006650FE add esp,4
00665101 lea eax,[y]
00665104 push eax
00665105 push offset string "%d" (0667B38h)
0066510A call _scanf (06613A2h)
0066510F add esp,8

//printf("x + y = %d\n", x + y);
00665112 mov eax,dword ptr [x]
00665115 add eax,dword ptr [y]
00665118 push eax
00665119 push offset string "x + y = %d\n" (0667CF0h)
0066511E call _printf (06613ACh)
00665123 add esp,8

//printf("x - y = %d\n", x - y);
00665126 mov eax,dword ptr [x]
00665129 sub eax,dword ptr [y]
0066512C push eax
0066512D push offset string "x - y = %d\n" (0667CE0h)
00665132 call _printf (06613ACh)
00665137 add esp,8

//printf("x * y = %d\n", x * y);
0066513A mov eax,dword ptr [x]
0066513D imul eax,dword ptr [y]
00665141 push eax
00665142 push offset string "x * y = %d\n" (0667CFCh)
00665147 call _printf (06613ACh)
0066514C add esp,8

//printf("x / y = %d\n", x / y);
0066514F mov eax,dword ptr [x]
00665152 cdq
00665153 idiv eax,dword ptr [y]
00665156 push eax
00665157 push offset string "x / y = %d\n" (0667E28h)
0066515C call _printf (06613ACh)
00665161 add esp,8

//printf("x %% y = %d\n", x % y);
00665164 mov eax,dword ptr [x]
00665167 cdq
00665168 idiv eax,dword ptr [y]
0066516B push edx
0066516C push offset string "x %% y = %d\n" (0667E34h)
00665171 call _printf (06613ACh)
00665176 add esp,8

//return 0;
00665179 xor eax,eax

0066517B push edx
0066517C mov ecx,ebp
0066517E push eax
0066517F lea edx,ds:[6651ACh]
00665185 call @_RTC_CheckStackVars@8 (06611D1h)
0066518A pop eax
0066518B pop edx
0066518C pop edi
0066518D pop esi
0066518E pop ebx
0066518F mov ecx,dword ptr [ebp-4]
00665192 xor ecx,ebp
00665194 call @__security_check_cookie@4 (066113Bh)
00665199 add esp,0DCh
0066519F cmp ebp,esp
006651A1 call __RTC_CheckEsp (0661230h)
006651A6 mov esp,ebp
006651A8 pop ebp
006651A9 ret

反汇编(release)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
00141080     push        ebp  
00141081 mov ebp,esp
00141083 sub esp,0Ch
00141086 mov eax,dword ptr [__security_cookie (0143000h)]
0014108B xor eax,ebp
0014108D mov dword ptr [ebp-4],eax

//puts("请输入两个整数。");
00141090 push offset string "\xc7\xeb\xca\xe4\xc8\xeb\xc1\xbd\xb8\xf6\xd5\xfb\xca\xfd\xa1\xa3" (0142108h)
00141095 call dword ptr [__imp__puts (01420B8h)]

//printf("整数x:"); scanf("%d", &x);
0014109B push offset string "\xd5\xfb\xca\xfdx\xa3\xba" (014211Ch)
001410A0 call printf (0141020h)
001410A5 lea eax,[x]
001410A8 push eax
001410A9 push offset string "%d" (0142124h)
001410AE call scanf (0141050h)

//printf("整数y:"); scanf("%d", &y);
001410B3 push offset string "\xd5\xfb\xca\xfdy\xa3\xba" (0142128h)
001410B8 call printf (0141020h)
001410BD lea eax,[y]
001410C0 push eax
001410C1 push offset string "%d" (0142124h)
001410C6 call scanf (0141050h)

//printf("x + y = %d\n", x + y);
001410CB mov eax,dword ptr [y]
001410CE add eax,dword ptr [x]
001410D1 push eax
001410D2 push offset string "x + y = %d\n" (0142130h)
001410D7 call printf (0141020h)

//printf("x - y = %d\n", x - y);
001410DC mov eax,dword ptr [x]
001410DF sub eax,dword ptr [y]
001410E2 push eax
001410E3 push offset string "x - y = %d\n" (014213Ch)
001410E8 call printf (0141020h)

//printf("x * y = %d\n", x * y);
001410ED mov eax,dword ptr [y]
001410F0 imul eax,dword ptr [x]
001410F4 push eax
001410F5 push offset string "x * y = %d\n" (0142148h)
001410FA call printf (0141020h)

//printf("x / y = %d\n", x / y);
001410FF mov eax,dword ptr [x]
00141102 cdq
00141103 idiv eax,dword ptr [y]
00141106 push eax
00141107 push offset string "x / y = %d\n" (0142154h)
0014110C call printf (0141020h)

//printf("x %% y = %d\n", x % y);
00141111 mov eax,dword ptr [x]
00141114 cdq
00141115 idiv eax,dword ptr [y]
00141118 push edx
00141119 push offset string "x %% y = %d\n" (0142160h)
0014111E call printf (0141020h)

//return 0;
00141123 mov ecx,dword ptr [ebp-4]
00141126 add esp,44h
00141129 xor ecx,ebp
0014112B xor eax,eax
0014112D call __security_check_cookie (0141136h)
00141132 mov esp,ebp
00141134 pop ebp
00141135 ret

硬编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
55                   push        ebp  
8B EC mov ebp,esp
81 EC DC 00 00 00 sub esp,0DCh
53 push ebx
56 push esi
57 push edi
8D 7D E4 lea edi,[ebp-1Ch]
B9 07 00 00 00 mov ecx,7
B8 CC CC CC CC mov eax,0CCCCCCCCh
F3 AB rep stos dword ptr es:[edi]
A1 20 A0 66 00 mov eax,dword ptr [__security_cookie (066A020h)]
33 C5 xor eax,ebp
89 45 FC mov dword ptr [ebp-4],eax
B9 08 C0 66 00 mov ecx,offset _FC42537F_mjc@cpp (066C008h)
E8 48 C2 FF FF call @__CheckForDebuggerJustMyCode@4 (0661307h)
8B F4 mov esi,esp
68 D8 7B 66 00 push offset string "\xc7\xeb\xca\xe4\xc8\xeb\xc1\xbd\xb8\xf6\xd5\xfb\xca\xfd\xa1\xa3" )
FF 15 70 B1 66 00 call dword ptr [__imp__puts (066B170h)]
83 C4 04 add esp,4
3B F4 cmp esi,esp
E8 5A C1 FF FF call __RTC_CheckEsp (0661230h)
68 30 7B 66 00 push offset string "\xd5\xfb\xca\xfdx\xa3\xba" (0667B30h)
E8 CC C2 FF FF call _printf (06613ACh)
83 C4 04 add esp,4
8D 45 F4 lea eax,[x]
50 push eax
68 38 7B 66 00 push offset string "%d" (0667B38h)
E8 B1 C2 FF FF call _scanf (06613A2h)
83 C4 08 add esp,8
68 EC 7B 66 00 push offset string "\xd5\xfb\xca\xfdy\xa3\xba" (0667BECh)
E8 AE C2 FF FF call _printf (06613ACh)
83 C4 04 add esp,4
8D 45 E8 lea eax,[y]
50 push eax
68 38 7B 66 00 push offset string "%d" (0667B38h)
E8 93 C2 FF FF call _scanf (06613A2h)
83 C4 08 add esp,8
8B 45 F4 mov eax,dword ptr [x]
03 45 E8 add eax,dword ptr [y]
50 push eax
68 F0 7C 66 00 push offset string "x + y = %d\n" (0667CF0h)
E8 89 C2 FF FF call _printf (06613ACh)
83 C4 08 add esp,8
8B 45 F4 mov eax,dword ptr [x]
2B 45 E8 sub eax,dword ptr [y]
50 push eax
68 E0 7C 66 00 push offset string "x - y = %d\n" (0667CE0h)
E8 75 C2 FF FF call _printf (06613ACh)
83 C4 08 add esp,8
8B 45 F4 mov eax,dword ptr [x]
0F AF 45 E8 imul eax,dword ptr [y]
50 push eax
68 FC 7C 66 00 push offset string "x * y = %d\n" (0667CFCh)
E8 60 C2 FF FF call _printf (06613ACh)
83 C4 08 add esp,8
8B 45 F4 mov eax,dword ptr [x]
99 cdq
F7 7D E8 idiv eax,dword ptr [y]
50 push eax
68 28 7E 66 00 push offset string "x / y = %d\n" (0667E28h)
E8 4B C2 FF FF call _printf (06613ACh)
83 C4 08 add esp,8
8B 45 F4 mov eax,dword ptr [x]
99 cdq
F7 7D E8 idiv eax,dword ptr [y]
52 push edx
68 34 7E 66 00 push offset string "x %% y = %d\n" (0667E34h)
E8 36 C2 FF FF call _printf (06613ACh)
83 C4 08 add esp,8
33 C0 xor eax,eax
52 push edx
8B CD mov ecx,ebp
50 push eax
8D 15 AC 51 66 00 lea edx,ds:[6651ACh]
E8 47 C0 FF FF call @_RTC_CheckStackVars@8 (06611D1h)
58 pop eax
5A pop edx
5F pop edi
5E pop esi
5B pop ebx
8B 4D FC mov ecx,dword ptr [ebp-4]
33 CD xor ecx,ebp
E8 A2 BF FF FF call @__security_check_cookie@4 (066113Bh)
81 C4 DC 00 00 00 add esp,0DCh
3B EC cmp ebp,esp
E8 8A C0 FF FF call __RTC_CheckEsp (0661230h)
8B E5 mov esp,ebp
5D pop ebp
C3 ret

取商:

1
2
3
4
mov eax,被除数
cdq //扩展符号位
idiv eax,除数
push eax //最终的商存在eax中

取余数:

1
2
3
4
mov eax,被除数
cdq //扩展符号位
idiv eax,除数
push edx //最终的余数存在edx中

乘法运算符和加减运算符
24

除法运算的商和余数
25
26

使用 printf 函数输出 %
27

获取整数的最后一位数字

显示读取出的整数的最后一位数字。

代码清单2-2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*程序名:list0202.c*/
/*显示读取出的整数的最后一位数字*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int x;

printf("请输入一个整数:");
scanf("%d", &x);

printf("最后一位是%d。\n", x % 10);
return 0;
}

反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//printf("最后一位是%d。\n", x % 10);
00FF10A8 8B 4D F8 mov ecx,dword ptr [x]
00FF10AB B8 67 66 66 66 mov eax,66666667h
00FF10B0 F7 E9 imul ecx
00FF10B2 C1 FA 02 sar edx,2
00FF10B5 8B C2 mov eax,edx
00FF10B7 C1 E8 1F shr eax,1Fh
00FF10BA 03 C2 add eax,edx
00FF10BC 8D 04 80 lea eax,[eax+eax*4]
00FF10BF 03 C0 add eax,eax
00FF10C1 2B C8 sub ecx,eax
00FF10C3 51 push ecx
00FF10C4 68 20 21 FF 00 push offset string "\xd7\xee\xba\xf3\xd2\xbb\xce\xbb\xca\xc7%d\xa1\xa3\n" (0FF2120h)
00FF10C9 E8 52 FF FF FF call printf (0FF1020h)

被除数/除数=商…余;余数=被除数-除数*商,至于 eax 赋值 66666667h,暂时还不理解。

28

多个转换说明

读取两个整数,并显示它们的商和余数。

代码清单2-3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*程序名:list0203.c*/
/*读取两个整数,显示它们的商和余数*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int a,b;

puts("请输入两个整数。");
printf("整数a:"); scanf("%d", &a);
printf("整数b:"); scanf("%d", &b);

printf("a除以b得%d余%d。\n", a / b, a % b);
return 0;
}

反汇编

1
2
3
4
5
6
7
8
9
10
11
//printf("a除以b得%d余%d。\n", a / b, a % b);
001210CB 8B 45 F8 mov eax,dword ptr [a]
001210CE 99 cdq
001210CF F7 7D F4 idiv eax,dword ptr [b]
001210D2 8B 45 F8 mov eax,dword ptr [a]
001210D5 52 push edx
001210D6 99 cdq
001210D7 F7 7D F4 idiv eax,dword ptr [b]
001210DA 50 push eax
001210DB 68 30 21 12 00 push offset string "a\xb3\xfd\xd2\xd4b\xb5\xc3%d\xd3\xe0%d\xa1\xa3\n" (0122130h)
001210E0 E8 3B FF FF FF call printf (0121020h)

做了两次除法运算。

单目运算

29

对读取的整数值进行符号取反操作,并输出结果。

代码清单2-4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*程序名:list0204.c*/
/*对读取的整数值进行符号取反操作,并输出结果。*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int num;

printf("请输入一个整数:");
scanf("%d",&num);

printf("符号取反之后的值是%d。\n", -num);
return 0;
}

反汇编

1
2
3
4
5
6
7
//printf("符号取反之后的值是%d。\n", -num);
009B50DD 8B 45 F4 mov eax,dword ptr [num]
009B50E0 F7 D8 neg eax
009B50E2 50 push eax
009B50E3 68 D8 7C 9B 00 push offset string "\xb7\xfb\xba\xc5\xc8\xa1\xb7\xb4\xd6\xae\xba\xf3\xb5\xc4\xd6\xb5\xca\xc7%d\xa1\xa3\n" (09B7CD8h)
009B50E8 E8 BF C2 FF FF call _printf (09B13ACh)
009B50ED 83 C4 08 add esp,8

使用 neg 指令实现取反操作

赋值运算符: =
表达式: a+b
赋值表达式: c=a+b

数据类型

求平均值

读取两个整数,求出它们的平均值

代码清单2-5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*程序名:list0205.c*/
/*读取两个整数,显示它们的平均值*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int a,b;

puts("请输入两个整数。");
printf("整数a:"); scanf("%d", &a);
printf("整数b:"); scanf("%d", &b);

printf("它们的平均值是%d。\n", (a + b) / 2);
return 0;
}

反汇编

1
2
3
4
5
6
7
8
9
10
//printf("它们的平均值是%d。\n", (a + b) / 2);
00F35112 8B 45 F4 mov eax,dword ptr [a]
00F35115 03 45 E8 add eax,dword ptr [b]
00F35118 99 cdq
00F35119 2B C2 sub eax,edx
00F3511B D1 F8 sar eax,1
00F3511D 50 push eax
00F3511E 68 DC 7C F3 00 push offset string "\xcb\xfc\xc3\xc7\xb5\xc4\xc6\xbd\xbe\xf9\xd6\xb5\xca\xc7%d\xa1\xa3\n" (0F37CDCh)
00F35123 E8 84 C2 FF FF call _printf (0F313ACh)
00F35128 83 C4 08 add esp,8

SAR 右移 1 位,实现平均值。

整数和浮点数

C语言中以浮点数的形式来表示实数,double 类型是双精度浮点数类型。

代清单2-6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*程序名:list0206.c*/
/*整数和浮点数*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int n;
double x;

n = 9.99;
x = 9.99;

printf("int 型变量 n 的值:%d\n",n);
printf("n / 2:%d\n",n/2);

printf("double型变量x的值:%f\n", x);
printf("x/2.0:%f\n", x / 2.0);

return 0;
}

另外需要注意的是,在使用 printf 函数输出 double 型值的时候,转换说明本那个使用%d,而要使用 %f。

反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//printf("double型变量x的值:%f\n", x);
005943E0 83 EC 08 sub esp,8
005943E3 F2 0F 10 45 E8 movsd xmm0,mmword ptr [x]
005943E8 F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
005943ED 68 28 7E 59 00 push offset string "double\xd0\xcd\xb1\xe4\xc1\xbfx\xb5\xc4\xd6\xb5\xa3\xba%f\n" (0597E28h)
005943F2 E8 B5 CF FF FF call _printf (05913ACh)
005943F7 83 C4 0C add esp,0Ch

//printf("x/2.0:%f\n", x / 2.0);
005943FA F2 0F 10 45 E8 movsd xmm0,mmword ptr [x]
005943FF F2 0F 5E 05 D8 7B 59 00 divsd xmm0,mmword ptr [__real@4000000000000000 (0597BD8h)]
00594407 83 EC 08 sub esp,8
0059440A F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
0059440F 68 EC 7B 59 00 push offset string "x/2.0:%f\n" (0597BECh)
00594414 E8 93 CF FF FF call _printf (05913ACh)
00594419 83 C4 0C add esp,0Ch

double占8字节大小。这里使用 movsd 指令将浮点值 x 存储到 FPU 寄存器栈中,使用 divsd 指令做浮点数的除法运算。

整型常量和浮点型常量

直接在程序中指定数值的常量也有类型的区别。像 5 和 37 这样的常量,它们都是整数类型的,所以称为 整型常量。像 3.14 这样包含小数的常量,称为 浮点型常量

Double类型的运算

编写一段程序,读取两个实数值,显示它们的和、差、积、商。

代码清单2-7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*程序名:list0207.c*/
/*读取两个实数值,用实数显示出它们的和、差、积、商*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
double vx, vy;
puts("请输入两个数。");
printf("实数vx: "); scanf("%lf", &vx);
printf("实数vy: "); scanf("%lf", &vy);

printf("vx + vy = %f\n", vx + vy);
printf("vx - vy = %f\n", vx - vy);
printf("vx * vy = %f\n", vx * vy);
printf("vx / vy = %f\n", vx / vy);
return 0;
}

反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//printf("vx + vy = %f\n", vx + vy);
00A55112 F2 0F 10 45 F0 movsd xmm0,mmword ptr [vx]
00A55117 F2 0F 58 45 E0 addsd xmm0,mmword ptr [vy]
00A5511C 83 EC 08 sub esp,8
00A5511F F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00A55124 68 D8 7C A5 00 push offset string "vx + vy = %f\n" (0A57CD8h)
00A55129 E8 7E C2 FF FF call _printf (0A513ACh)
00A5512E 83 C4 0C add esp,0Ch

//printf("vx - vy = %f\n", vx - vy);
00A55131 F2 0F 10 45 F0 movsd xmm0,mmword ptr [vx]
00A55136 F2 0F 5C 45 E0 subsd xmm0,mmword ptr [vy]
00A5513B 83 EC 08 sub esp,8
00A5513E F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00A55143 68 2C 7E A5 00 push offset string "vx - vy = %f\n" (0A57E2Ch)
00A55148 E8 5F C2 FF FF call _printf (0A513ACh)
00A5514D 83 C4 0C add esp,0Ch

//printf("vx * vy = %f\n", vx * vy);
00A55150 F2 0F 10 45 F0 movsd xmm0,mmword ptr [vx]
00A55155 F2 0F 59 45 E0 mulsd xmm0,mmword ptr [vy]
00A5515A 83 EC 08 sub esp,8
00A5515D F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00A55162 68 3C 7E A5 00 push offset string "vx * vy = %f\n" (0A57E3Ch)
00A55167 E8 40 C2 FF FF call _printf (0A513ACh)
00A5516C 83 C4 0C add esp,0Ch

//printf("vx / vy = %f\n", vx / vy);
00A5516F F2 0F 10 45 F0 movsd xmm0,mmword ptr [vx]
00A55174 F2 0F 5E 45 E0 divsd xmm0,mmword ptr [vy]
00A55179 83 EC 08 sub esp,8
00A5517C F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00A55181 68 4C 7E A5 00 push offset string "vx / vy = %f\n" (0A57E4Ch)
00A55186 E8 21 C2 FF FF call _printf (0A513ACh)
00A5518B 83 C4 0C add esp,0Ch

30

浮点数算术指令:addsd、subsd、mulsd、divsd

数据类型和运算

进行整数/整数运算的时候,商的小时部分会被舍弃,但是浮点数之间的运算,就不会进行舍弃处理。

31

这个涉及到数据类型的转换,下面演示的是两个不同类型的变量类型转换的案例。

案例演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*程序名:list0207_1.c*/
/*演示整数类型如何扩展为double类型*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int x=4;
double vx=2.0, vy;
puts("请输入两个数。");
//printf("实数vx: "); scanf("%lf", &vx);
//printf("实数vy: "); scanf("%lf", &vy);

printf("vx + x = %f\n", vx + x);
printf("vx - x = %f\n", vx - x);
printf("vx * x = %f\n", vx * x);
printf("vx / x = %f\n", vx / x);
return 0;
}

反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//printf("vx + x = %f\n", vx + x);
00325240 F2 0F 2A 45 F8 cvtsi2sd xmm0,dword ptr [x]
00325245 F2 0F 58 45 E8 addsd xmm0,mmword ptr [vx]
0032524A 83 EC 08 sub esp,8
0032524D F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00325252 68 D8 7B 32 00 push offset string "vx + x = %f\n" (0327BD8h)
00325257 E8 50 C1 FF FF call _printf (03213ACh)
0032525C 83 C4 0C add esp,0Ch

//printf("vx - x = %f\n", vx - x);
0032525F F2 0F 2A 45 F8 cvtsi2sd xmm0,dword ptr [x]
00325264 F2 0F 10 4D E8 movsd xmm1,mmword ptr [vx]
00325269 F2 0F 5C C8 subsd xmm1,xmm0
0032526D 83 EC 08 sub esp,8
00325270 F2 0F 11 0C 24 movsd mmword ptr [esp],xmm1
00325275 68 8C 7F 32 00 push offset string "vx - x = %f\n" (0327F8Ch)
0032527A E8 2D C1 FF FF call _printf (03213ACh)
0032527F 83 C4 0C add esp,0Ch

//printf("vx * x = %f\n", vx * x);
00325282 F2 0F 2A 45 F8 xmm0,dword ptr [x]
00325287 F2 0F 59 45 E8 mulsd xmm0,mmword ptr [vx]
0032528C 83 EC 08 sub esp,8 cvtsi2sd
0032528F F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00325294 68 E8 7B 32 00 push offset string "vx * x = %f\n" (0327BE8h)
00325299 E8 0E C1 FF FF call _printf (03213ACh)
0032529E 83 C4 0C add esp,0Ch

//printf("vx / x = %f\n", vx / x);
003252A1 F2 0F 2A 45 F8 cvtsi2sd xmm0,dword ptr [x]
003252A6 F2 0F 10 4D E8 movsd xmm1,mmword ptr [vx]
003252AB F2 0F 5E C8 divsd xmm1,xmm0
003252AF 83 EC 08 sub esp,8
003252B2 F2 0F 11 0C 24 movsd mmword ptr [esp],xmm1
003252B7 68 D8 7C 32 00 push offset string "vx / x = %f\n" (0327CD8h)
003252BC E8 EB C0 FF FF call _printf (03213ACh)
003252C1 83 C4 0C add esp,0Ch

操作数的类型不同时,脚下的数据类型的操作数会转换为较大的数据类型,然后再进行运算。反汇编中使用 SEE2 指令集中的 cvtsi2sd 指令:取出最低位的 64 位整型,并将其转换位一个浮点值。内部指令:_mm_cvtsi64_sd

SEE 指令集

第一个支持SSE的CPU是Pentium III,在FPU与SSE之间共享执行支持。当编译出来的软件能够交叉的同时以FPU与SSE运作,Pentium III并无法在同一个周期中同时执行FPU与SSE。这个限制降低了指令流水线的有效性,不过XMM寄存器能够让SIMD与标量浮点运算混合执行,而不会因为切换MMX/浮点模式而产生性能的折损。

SSE的全称是 Sreaming SIMD Extensions, 它是一组Intel CPU指令,用于像信号处理、科学计算或者3D图形计算一样的应用。其优势包括:更高分辨率的图像浏览和处理、高质量音频、MPEG2视频、同时MPEG2加解密;语音识别占用更少CPU资源;更高精度和更快响应速度。使用SSE指令集,主要是通过8个128-bit的寄存器:xmm0到xmm7 来完成的。在Linux下可以使用cat /proc/cpuinfo来查看CPU支持哪些指令集。 SSE的指令集是X86架构CPU特有的,对于ARM架构、MIPS架构等CPU是不支持的,所以使用了SSE指令集的程序,是不具备可移植标准的。

代码清单2-8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*程序名:list0208.c*/
/*验证数据类型和运算*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int n1, n2, n3, n4;
double d1, d2, d3, d4;

n1 = 5 / 2;
n2 = 5.0 / 2.0;
n3 = 5.0 / 2;
n4 = 5 / 2.0;

d1 = 5 / 2;
d2 = 5.0 / 2.0;
d3 = 5.0 / 2;
d4 = 5 / 2.0;

printf("n1 = %d\n", n1);
printf("n2 = %d\n", n2);
printf("n3 = %d\n", n3);
printf("n4 = %d\n", n4);

printf("d1 = %f\n", d1);
printf("d2 = %f\n", d2);
printf("d3 = %f\n", d3);
printf("d4 = %f\n", d4);

return 0;
}

反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//n1 = 5 / 2;
00735215 C7 45 F8 02 00 00 00 mov dword ptr [n1],2

//n2 = 5.0 / 2.0;
0073521C C7 45 EC 02 00 00 00 mov dword ptr [n2],2

//n3 = 5.0 / 2;
00735223 C7 45 E0 02 00 00 00 mov dword ptr [n3],2

//n4 = 5 / 2.0;
0073522A C7 45 D4 02 00 00 00 mov dword ptr [n4],2

//d1 = 5 / 2;
00735231 F2 0F 10 05 30 7B 73 00 movsd xmm0,mmword ptr [__real@4000000000000000 (0737B30h)]
00735239 F2 0F 11 45 C4 movsd mmword ptr [d1],xmm0

//d2 = 5.0 / 2.0;
0073523E F2 0F 10 05 38 7E 73 00 movsd xmm0,mmword ptr [__real@4004000000000000 (0737E38h)]
00735246 F2 0F 11 45 B4 movsd mmword ptr [d2],xmm0

//d3 = 5.0 / 2;
0073524B F2 0F 10 05 38 7E 73 00 movsd xmm0,mmword ptr [__real@4004000000000000 (0737E38h)]
00735253 F2 0F 11 45 A4 movsd mmword ptr [d3],xmm0

//d4 = 5 / 2.0;
00735258 F2 0F 10 05 38 7E 73 00 movsd xmm0,mmword ptr [__real@4004000000000000 (0737E38h)]
00735260 F2 0F 11 45 94 movsd mmword ptr [d4],xmm0

//printf("n1 = %d\n", n1);
00735265 8B 45 F8 mov eax,dword ptr [n1]
00735268 50 push eax
00735269 68 F0 7C 73 00 push offset string "n1 = %d\n" (0737CF0h)
0073526E E8 39 C1 FF FF call _printf (07313ACh)
00735273 83 C4 08 add esp,8

//printf("n2 = %d\n", n2);
00735276 8B 45 EC mov eax,dword ptr [n2]
00735279 50 push eax
0073527A 68 D8 7B 73 00 push offset string "n2 = %d\n" (0737BD8h)
0073527F E8 28 C1 FF FF call _printf (07313ACh)
00735284 83 C4 08 add esp,8

//printf("n3 = %d\n", n3);
00735287 8B 45 E0 mov eax,dword ptr [n3]
0073528A 50 push eax
0073528B 68 8C 7F 73 00 push offset string "n3 = %d\n" (0737F8Ch)
00735290 E8 17 C1 FF FF call _printf (07313ACh)
00735295 83 C4 08 add esp,8

//printf("n4 = %d\n", n4);
00735298 8B 45 D4 mov eax,dword ptr [n4]
0073529B 50 push eax
0073529C 68 E8 7B 73 00 push offset string "n4 = %d\n" (0737BE8h)
007352A1 E8 06 C1 FF FF call _printf (07313ACh)
007352A6 83 C4 08 add esp,8

//printf("d1 = %f\n", d1);
007352A9 83 EC 08 sub esp,8
007352AC F2 0F 10 45 C4 movsd xmm0,mmword ptr [d1]
007352B1 F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
007352B6 68 D8 7C 73 00 push offset string "d1 = %f\n" (0737CD8h)
007352BB E8 EC C0 FF FF call _printf (07313ACh)
007352C0 83 C4 0C add esp,0Ch

//printf("d2 = %f\n", d2);
007352C3 83 EC 08 sub esp,8
007352C6 F2 0F 10 45 B4 movsd xmm0,mmword ptr [d2]
007352CB F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
007352D0 68 E4 7C 73 00 push offset string "d2 = %f\n" (0737CE4h)
007352D5 E8 D2 C0 FF FF call _printf (07313ACh)
007352DA 83 C4 0C add esp,0Ch

//printf("d3 = %f\n", d3);
007352DD 83 EC 08 sub esp,8
007352E0 F2 0F 10 45 A4 movsd xmm0,mmword ptr [d3]
007352E5 F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
007352EA 68 FC 7C 73 00 push offset string "d3 = %f\n" (0737CFCh)
007352EF E8 B8 C0 FF FF call _printf (07313ACh)
007352F4 83 C4 0C add esp,0Ch

//printf("d4 = %f\n", d4);
007352F7 83 EC 08 sub esp,8
007352FA F2 0F 10 45 94 movsd xmm0,mmword ptr [d4]
007352FF F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00735304 68 28 7E 73 00 push offset string "d4 = %f\n" (0737E28h)
00735309 E8 9E C0 FF FF call _printf (07313ACh)
0073530E 83 C4 0C add esp,0Ch

上面的是书中的例子(2-8),该例子演示:操作数的类型不同时,较小的数据类型操作数会转换成较大的数据类型然后再进行运算。查看 2-8 的反汇编,发现这些运算编译器在编译过程中就算好了结果,程序运行时,其类型并没有转换。因此 2-8 的例子还有所欠缺。

32

这一节的知识点主要是解释:实数常量存储到 int 类型中无法保留小数点后面的值,但是 double 类型是可以存储小数和整数。主要原因就是 double 类型占的字节大于 int 类型占的字节。

数据类型的转换

修改代码清单2-5,尝试输出小数。

代码清单2-9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*程序名:list0209.c*/
/*读取两个整数,并用浮点数显示它们的平均值。*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int a, b;

puts("请输入两个整数。");
printf("整数a:"); scanf("%d", &a);
printf("整数b:"); scanf("%d", &b);

printf("它们的平均值是%f。\n", (a + b) / 2.0);
return 0;
}
反汇编
1
2
3
4
5
6
7
8
9
10
//printf("它们的平均值是%f。\n", (a + b) / 2.0);
8B 45 F4 mov eax,dword ptr [a]
03 45 E8 add eax,dword ptr [b]
F2 0F 2A C0 cvtsi2sd xmm0,eax
F2 0F 5E 05 30 7B B1 00 divsd xmm0,mmword ptr [__real@4000000000000000 (0B17B30h)]
83 EC 08 sub esp,8
F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
68 90 7F B1 00 push offset string "\xcb\xfc\xc3\xc7\xb5\xc4\xc6\xbd\xbe\xf9\xd6\xb5\xca\xc7%f\xa1\xa3\n" (0B17F90h)
E8 76 C2 FF FF call _printf (0B113ACh)
83 C4 0C add esp,0Ch

printf函数类型转换和之前演示的数据类型转换的案例一样,使用 cvtsi2sd 指令,将 eax 寄存器的整数值,扩展为浮点值并存储到 xmm0 寄存器中。

代码清单2-10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*程序名:list0210.c*/
/*读取两个整数,并用实数显示出它们的平均值(类型转换)。*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int a, b;

puts("请输入两个整数。");
printf("整数a:"); scanf("%d", &a);
printf("整数b:"); scanf("%d", &b);

printf("它们的平均值是%f。\n", (double)(a + b) / 2);
return 0;
}

反汇编

1
2
3
4
5
6
7
8
9
10
//printf("它们的平均值是%f。\n", (double)(a + b) / 2);
8B 45 F4 mov eax,dword ptr [a]
03 45 E8 add eax,dword ptr [b]
F2 0F 2A C0 cvtsi2sd xmm0,eax
F2 0F 5E 05 30 7B 6A 00 divsd xmm0,mmword ptr [__real@4000000000000000 (06A7B30h)]
83 EC 08 sub esp,8
F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
68 90 7F 6A 00 push offset string "\xcb\xfc\xc3\xc7\xb5\xc4\xc6\xbd\xbe\xf9\xd6\xb5\xca\xc7%f\xa1\xa3\n" (06A7F90h)
E8 76 C2 FF FF call _printf (06A13ACh)
83 C4 0C add esp,0Ch

“(double)(a + b) / 2” 和 “(a + b) / 2.0” 两种写法汇编表现形式都是一样的。

转换说明

读取三个整数,并显示它们的和以及平均值的的程序。

代码清单2-11

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*程序名:list0211.c*/
/*读取两个整数,并显示它们的合计值和平均值。*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int a, b, c;
int sum;
double ave;

puts("请输入三个整数。");
printf("整数a:"); scanf("%d", &a);
printf("整数b:"); scanf("%d", &b);
printf("整数c:"); scanf("%d", &c);

sum = a + b + c;
ave = (double)sum / 3;

printf("它们的合计值是%5d。\n", sum);
printf("它们的平均值是%5.1f。\n", ave);
return 0;
}

反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//sum = a + b + c;
8B 45 F4 mov eax,dword ptr [a]
03 45 E8 add eax,dword ptr [b]
03 45 DC add eax,dword ptr [c]
89 45 D0 mov dword ptr [sum],eax

//ave = (double)sum / 3;
F2 0F 2A 45 D0 cvtsi2sd xmm0,dword ptr [sum]
F2 0F 5E 05 30 7B 60 00 divsd xmm0,mmword ptr [__real@4008000000000000 (0607B30h)]
F2 0F 11 45 C0 movsd mmword ptr [ave],xmm0

//printf("它们的合计值是%5d。\n", sum);
8B 45 D0 mov eax,dword ptr [sum]
50 push eax
68 D8 7C 60 00 push offset string "\xcb\xfc\xc3\xc7\xb5\xc4\xba\xcf\xbc\xc6\xd6\xb5\xca\xc7%5d\xa1\xa3\n" (0607CD8h)
E8 50 C2 FF FF call _printf (06013ACh)
83 C4 08 add esp,8

//printf("它们的平均值是%5.1f。\n", ave);
83 EC 08 sub esp,8
F2 0F 10 45 C0 movsd xmm0,mmword ptr [ave]
F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
68 F0 7C 60 00 push offset string "\xcb\xfc\xc3\xc7\xb5\xc4\xc6\xbd\xbe\xf9\xd6\xb5\xca\xc7%5.1f\xa1\xa3\n" (0607CF0h)
E8 36 C2 FF FF call _printf (06013ACh)
83 C4 0C add esp,0Ch

33

另外,如果设定了 “-”,数据会左对齐显示,未设定则会右对齐显示。

代码清单2-12

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*程序名:list0212.c*/
/*格式化整数和浮点数*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
printf("[%d]\n", 123);
printf("[%.4d]\n", 123);
printf("[%4d]\n", 123);
printf("[%04d]\n", 123);
printf("[-4d]\n\n", 123);

printf("[%d]\n", 12345);
printf("[%.3d]\n", 12345);
printf("[%3d]\n", 12345);
printf("[%03d]\n", 12345);
printf("[%-3d]\n\n", 12345);

printf("[%f]\n", 123.13);
printf("[%.1f]\n", 123.13);
printf("[%6.1f]\n\n", 123.13);

printf("[%f]\n", 123.13);
printf("[%.1f]\n", 123.13);
printf("[%4.1f]\n\n", 123.13);
return 0;
}

34

反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//printf("[%d]\n", 123);
00D45211 6A 7B push 7Bh
00D45213 68 40 7E D4 00 push offset string "[%d]\n" (0D47E40h)
00D45218 E8 8F C1 FF FF call _printf (0D413ACh)
00D4521D 83 C4 08 add esp,8

//printf("[%.4d]\n", 123);
00D45220 6A 7B push 7Bh
00D45222 68 D8 7B D4 00 push offset string "[%.4d]\n" (0D47BD8h)
00D45227 E8 80 C1 FF FF call _printf (0D413ACh)
00D4522C 83 C4 08 add esp,8

//printf("[%4d]\n", 123);
00D4522F 6A 7B push 7Bh
00D45231 68 E0 7B D4 00 push offset string "[%4d]\n" (0D47BE0h)
00D45236 E8 71 C1 FF FF call _printf (0D413ACh)
00D4523B 83 C4 08 add esp,8

//printf("[%04d]\n", 123);
00D4523E 6A 7B push 7Bh
00D45240 68 E8 7B D4 00 push offset string "[%04d]\n" (0D47BE8h)
00D45245 E8 62 C1 FF FF call _printf (0D413ACh)
00D4524A 83 C4 08 add esp,8

//printf("[-4d]\n\n", 123);
00D4524D 6A 7B push 7Bh
00D4524F 68 90 7F D4 00 push offset string "[-4d]\n\n" (0D47F90h)
00D45254 E8 53 C1 FF FF call _printf (0D413ACh)
00D45259 83 C4 08 add esp,8

//printf("[%d]\n", 12345);
00D4525C 68 39 30 00 00 push 3039h
00D45261 68 40 7E D4 00 push offset string "[%d]\n" (0D47E40h)
00D45266 E8 41 C1 FF FF call _printf (0D413ACh)
00D4526B 83 C4 08 add esp,8

//printf("[%.3d]\n", 12345);
00D4526E 68 39 30 00 00 push 3039h
00D45273 68 D8 7C D4 00 push offset string "[%.3d]\n" (0D47CD8h)
00D45278 E8 2F C1 FF FF call _printf (0D413ACh)
00D4527D 83 C4 08 add esp,8

//printf("[%3d]\n", 12345);
00D45280 68 39 30 00 00 push 3039h
00D45285 68 F0 7C D4 00 push offset string "[%3d]\n" (0D47CF0h)
00D4528A E8 1D C1 FF FF call _printf (0D413ACh)
00D4528F 83 C4 08 add esp,8

//printf("[%03d]\n", 12345);
00D45292 68 39 30 00 00 push 3039h
00D45297 68 F0 7B D4 00 push offset string "[%03d]\n" (0D47BF0h)
00D4529C E8 0B C1 FF FF call _printf (0D413ACh)
00D452A1 83 C4 08 add esp,8

//printf("[%-3d]\n\n", 12345);
00D452A4 68 39 30 00 00 push 3039h
00D452A9 68 E0 7C D4 00 push offset string "[%-3d]\n\n" (0D47CE0h)
00D452AE E8 F9 C0 FF FF call _printf (0D413ACh)
00D452B3 83 C4 08 add esp,8

//printf("[%f]\n", 123.13);
00D452B6 83 EC 08 sub esp,8
00D452B9 F2 0F 10 05 30 7B D4 00 movsd xmm0,mmword ptr [__real@405ec851eb851eb8 (0D47B30h)]
00D452C1 F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00D452C6 68 F8 7C D4 00 push offset string "[%f]\n" (0D47CF8h)
00D452CB E8 DC C0 FF FF call _printf (0D413ACh)
00D452D0 83 C4 0C add esp,0Ch

//printf("[%.1f]\n", 123.13);
00D452D3 83 EC 08 sub esp,8
00D452D6 F2 0F 10 05 30 7B D4 00 movsd xmm0,mmword ptr [__real@405ec851eb851eb8 (0D47B30h)]
00D452DE F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00D452E3 68 00 7D D4 00 push offset string "[%.1f]\n" (0D47D00h)
00D452E8 E8 BF C0 FF FF call _printf (0D413ACh)
00D452ED 83 C4 0C add esp,0Ch

//printf("[%6.1f]\n\n", 123.13);
00D452F0 83 EC 08 sub esp,8
00D452F3 F2 0F 10 05 30 7B D4 00 movsd xmm0,mmword ptr [__real@405ec851eb851eb8 (0D47B30h)]
00D452FB F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00D45300 68 28 7E D4 00 push offset string "[%6.1f]\n\n" (0D47E28h)
00D45305 E8 A2 C0 FF FF call _printf (0D413ACh)
00D4530A 83 C4 0C add esp,0Ch

//printf("[%f]\n", 123.13);
00D4530D 83 EC 08 sub esp,8
00D45310 F2 0F 10 05 30 7B D4 00 movsd xmm0,mmword ptr [__real@405ec851eb851eb8 (0D47B30h)]
00D45318 F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00D4531D 68 F8 7C D4 00 push offset string "[%f]\n" (0D47CF8h)
00D45322 E8 85 C0 FF FF call _printf (0D413ACh)
00D45327 83 C4 0C add esp,0Ch

//printf("[%.1f]\n", 123.13);
00D4532A 83 EC 08 sub esp,8
00D4532D F2 0F 10 05 30 7B D4 00 movsd xmm0,mmword ptr [__real@405ec851eb851eb8 (0D47B30h)]
00D45335 F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00D4533A 68 00 7D D4 00 push offset string "[%.1f]\n" (0D47D00h)
00D4533F E8 68 C0 FF FF call _printf (0D413ACh)
00D45344 83 C4 0C add esp,0Ch

//printf("[%4.1f]\n\n", 123.13);
00D45347 83 EC 08 sub esp,8
00D4534A F2 0F 10 05 30 7B D4 00 movsd xmm0,mmword ptr [__real@405ec851eb851eb8 (0D47B30h)]
00D45352 F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00D45357 68 34 7E D4 00 push offset string "[%4.1f]\n\n" (0D47E34h)
00D4535C E8 4B C0 FF FF call _printf (0D413ACh)
00D45361 83 C4 0C add esp,0Ch

35

总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*程序名:summary.c*/
/*第二章总结*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int a;
int b;

double r;

printf("整数a和b的值");
scanf("%d%d", &a, &b);

printf("a + b = %d\n", a + b);
printf("a - b = %d\n", a - b);
printf("a * b = %d\n", a * b);
printf("a / b = %d\n", a / b);
printf("a %% b = %d\n", a % b);

printf("(a + b)/2 = %d\n", (a + b) / 2);
printf("平均值 = %f\n\n", (double)(a + b) / 2);

printf("半径:");
scanf("%lf", &r);

printf("半径为%.3f的圆的面积是%.3f。\n", r, 3.14 * r * r);
return 0;
}

36

反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//printf("(a + b)/2 = %d\n", (a + b) / 2);
00B95318 8B 45 F4 mov eax,dword ptr [a]
00B9531B 03 45 E8 add eax,dword ptr [b]
00B9531E 99 cdq
00B9531F 2B C2 sub eax,edx
00B95321 D1 F8 sar eax,1
00B95323 50 push eax
00B95324 68 24 83 B9 00 push offset string "(a + b)/2 = %d\n" (0B98324h)
00B95329 E8 7E C0 FF FF call _printf (0B913ACh)
00B9532E 83 C4 08 add esp,8

//printf("平均值 = %f\n\n", (double)(a + b) / 2);
00B95331 8B 45 F4 mov eax,dword ptr [a]
00B95334 03 45 E8 add eax,dword ptr [b]
00B95337 F2 0F 2A C0 cvtsi2sd xmm0,eax
00B9533B F2 0F 5E 05 30 7B B9 00 divsd xmm0,mmword ptr [__real@4000000000000000 (0B97B30h)]
00B95343 83 EC 08 sub esp,8
00B95346 F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00B9534B 68 E0 7C B9 00 push offset string "\xc6\xbd\xbe\xf9\xd6\xb5 = %f\n\n" (0B97CE0h)
00B95350 E8 57 C0 FF FF call _printf (0B913ACh)
00B95355 83 C4 0C add esp,0Ch

//printf("半径:");
00B95358 68 F8 7C B9 00 push offset string "\xb0\xeb\xbe\xb6\xa3\xba" (0B97CF8h)
00B9535D E8 4A C0 FF FF call _printf (0B913ACh)
00B95362 83 C4 04 add esp,4

//scanf("%lf", &r);
00B95365 8D 45 D8 lea eax,[r]
00B95368 50 push eax
00B95369 68 00 7D B9 00 push offset string "%lf" (0B97D00h)
00B9536E E8 70 C0 FF FF call _scanf (0B913E3h)
00B95373 83 C4 08 add esp,8

//printf("半径为%.3f的圆的面积是%.3f。\n", r, 3.14 * r * r);
00B95376 F2 0F 10 05 F0 7B B9 00 movsd xmm0,mmword ptr [__real@40091eb851eb851f (0B97BF0h)]
00B9537E F2 0F 59 45 D8 mulsd xmm0,mmword ptr [r]
00B95383 F2 0F 59 45 D8 mulsd xmm0,mmword ptr [r]
00B95388 83 EC 08 sub esp,8
00B9538B F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00B95390 83 EC 08 sub esp,8
00B95393 F2 0F 10 45 D8 movsd xmm0,mmword ptr [r]
00B95398 F2 0F 11 04 24 movsd mmword ptr [esp],xmm0
00B9539D 68 B0 85 B9 00 push offset string "\xb0\xeb\xbe\xb6\xce\xaa%.3f\xb5\xc4\xd4\xb2\xb5\xc4\xc3\xe6\xbb\xfd\xca\xc7%.3f\xa1\xa3\n" (0B985B0h)
00B953A2 E8 05 C0 FF FF call _printf (0B913ACh)
00B953A7 83 C4 14 add esp,14h

课后练习

练习2-1

37

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*程序名:lx2-1.c*/
/*
编写一段程序,像下面输出那样读取两个整数,然后显示出前者是后者的百分之几。
请输入两个整数。
整数x:54
整数y:84
x的值是y的64%
*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int x, y;

puts("请输入两个整数:");
printf("整数x:", x); scanf("%d", &x);
printf("整数y:", y); scanf("%d", &y);

printf("x的值是y的%d%%\n", 100 - y + x);
return 0;
}

练习2-2

38

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*程序名:lx2-2.c*/
/*
编写一段程序,像下面输出那样读取两个整数,然后输出它们的和以及乘积。
请输入两个整数。
整数a:54
整数b:12
x与y的和是66,积是648
*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int x, y;

puts("请输入两个整数:");
printf("整数a:", x); scanf("%d", &x);
printf("整数b:", y); scanf("%d", &y);

printf("x与y的和是%d,积是%d\n", y + x, x * y);
return 0;
}

练习2-3

39

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*程序名:lx2-3.c*/
/*
编写一段程序,像下面输出那样显示读取的实数值。
请输入一个实数:57.3
你输入的是57.300000
*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
double x;

printf("请输入一个实数:");
scanf("%lf", &x);

printf("你输入的是%f\n", x);
return 0;
}

练习2-4

40

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*程序名:lx2-4.c*/
/*
编写程序对整型常量、浮点常量、int型变量和double型变量进行乘除等各种运算。
*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int x = 2;
double y = 2;
int z;
printf("请输入一个整数:"); scanf("%d", &z);

//整型变量对整数常量进行加减乘除
printf("%d + 2=%d\n", z, z + 2);
printf("%d - 2=%d\n", z, z - 2);
printf("%d * 2=%d\n", z, z * 2);
printf("%d / 2=%d\n", z, z / 2);
printf("%d %% 2=%d\n\n", z, z % 2);

//整型变量对浮点数常量进行加减乘除
printf("%d + 2.0=%lf\n", z, z + 2.0);
printf("%d - 2.0=%lf\n", z, z - 2.0);
printf("%d * 2.0=%lf\n", z, z * 2.0);
printf("%d / 2.0=%lf\n", z, z / 2.0);
printf("%d %% 2.0=%lf\n\n", z, (double)(z % 2));

//整型变量对整数变量进行加减乘除
printf("%d + x=%d\n", z, z + x);
printf("%d - x=%d\n", z, z - x);
printf("%d * x=%d\n", z, z * x);
printf("%d / x=%d\n", z, z / x);
printf("%d %% x=%d\n\n", z, z % x);

//整型变量对浮点数变量进行加减乘除
printf("%d + y=%lf\n", z, z + y);
printf("%d - y=%lf\n", z, z - y);
printf("%d * y=%lf\n", z, z * y);
printf("%d / y=%lf\n", z, z / y);
printf("%d %% y=%lf\n\n", z, (double)(z % (int)y));
return 0;
}

练习2-5

41

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*程序名:lx2-5.c*/
/*
编写一段程序,像下边那样读取整数的值,计算出前者是后者的百分之几,并用实数输出结果。
请输入两个整数。
整数a:
整数b:
a是b的%浮点数
*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int a, b;
puts("请输入两个整数。");
printf("整数a:"); scanf("%d", &a);
printf("整数b:"); scanf("%d", &b);

printf("a是b的%%%.2f", (double)(100 / b * a));
return 0;
}

练习2-6

42

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*程序名:lx2-6.c*/
/*
编写一段程序,像下边那样读取表示身高的整数值,显示出标准体重实数值。
标准体重根据 (身高-100)x0.9 进行计算,所得结果保留一位小数。
请输入您的身高:
您的标准体重是多少公斤。
*/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

int main(void)
{
int a;
double b;
printf("请输入您的身高:"); scanf("%d", &a);

b = (double)(a - 100) * 0.9;
printf("您的标准体重是%.1f公斤。", b);
return 0;
}
  • 本文标题:C语言语法入门-运算和数据类型
  • 本文作者:9unk
  • 创建时间:2023-05-07 11:00:00
  • 本文链接:https://9unkk.github.io/2023/05/07/c-yu-yan-yu-fa-ru-men-yun-suan-he-shu-ju-lei-xing/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!