注:
1.全部代码
/* show-bytes - prints byte representation of data */
/* $begin show-bytes */
#include <stdio.h>
/* $end show-bytes */
#include <stdlib.h>
#include <string.h>
/* $begin show-bytes */
typedef unsigned char *byte_pointer;
//typedef char *byte_pointer;
//typedef int *byte_pointer;
void show_bytes(byte_pointer start, size_t len) {
size_t i;
for (i = 0; i < len; i++)
printf("%p\t0x%.2x\n", &start[i], start[i]);
printf("\n");
}
void show_int(int x) {
show_bytes((byte_pointer) &x, sizeof(int));
}
void show_float(float x) {
show_bytes((byte_pointer) &x, sizeof(float));
}
void show_pointer(void *x) {
show_bytes((byte_pointer) &x, sizeof(void *));
}
/* $end show-bytes */
/* $begin test-show-bytes */
void test_show_bytes(int val) {
int ival = val;
//float fval = (float) ival;
double fval = (double) ival;
int *pval = &ival;
printf("Stack variable ival = %d\n", ival);
printf("(int)ival:\n");
show_int(ival);
printf("(float)ival:\n");
show_float(fval);
printf("&ival:\n");
show_pointer(pval);
}
/* $end test-show-bytes */
void simple_show_a() {
/* $begin simple-show-a */
int val = 0x87654321;
byte_pointer valp = (byte_pointer) &val;
show_bytes(valp, 1); /* A. */
show_bytes(valp, 2); /* B. */
show_bytes(valp, 3); /* C. */
/* $end simple-show-a */
}
void simple_show_b() {
/* $begin simple-show-b */
int val = 0x12345678;
byte_pointer valp = (byte_pointer) &val;
show_bytes(valp, 1); /* A. */
show_bytes(valp, 2); /* B. */
show_bytes(valp, 3); /* C. */
/* $end simple-show-b */
}
void float_eg() {
int x = 3490593;
float f = (float) x;
printf("For x = %d\n", x);
show_int(x);
show_float(f);
x = 3510593;
f = (float) x;
printf("For x = %d\n", x);
show_int(x);
show_float(f);
}
void string_ueg() {
/* $begin show-ustring */
const char *s = "ABCDEF";
show_bytes((byte_pointer) s, strlen(s));
/* $end show-ustring */
}
void string_leg() {
/* $begin show-lstring */
const char *s = "abcdef";
show_bytes((byte_pointer) s, strlen(s));
/* $end show-lstring */
}
void show_twocomp()
{
/* $begin show-twocomp */
short x = 12345;
short mx = -x;
show_bytes((byte_pointer) &x, sizeof(short));
show_bytes((byte_pointer) &mx, sizeof(short));
/* $end show-twocomp */
}
int main(int argc, char *argv[])
{
int val = 12345;
if (argc > 1) {
val = strtol(argv[1], NULL, 0);
printf("calling test_show_bytes\n");
test_show_bytes(val);
} else {
printf("calling show_twocomp\n");
show_twocomp();
printf("Calling simple_show_a\n");
simple_show_a();
printf("Calling simple_show_b\n");
simple_show_b();
printf("Calling float_eg\n");
float_eg();
printf("Calling string_ueg\n");
string_ueg();
printf("Calling string_leg\n");
string_leg();
}
return 0;
}
2.代码分析
(1)其中绿色字体为“头文件”,最后一行将“byte_pointer”定义为指向“unsigned char”类型的指针。
(2)主函数(如下图第110行)为带参数的函数的main()函数
“形参argc是整型变量,用于存放命令行中参数的个数,因为程序名也计算在内,所以argc的值至少为1。形参argv是字符指针数组,数组中的每一个元素都是一个字符串指针,指向命令行中的一个命令行参数。”
(3)第112行,定义一整型变量“val”并赋初值。 “argc>1”即当在命令行输入了参数时就做“if”下面的语句。
“strtol()”为C标准库<stdlib.h>里的函数(详细见我之前找到的博客),而在这里的用处,就是把命令行中的参数赋值给“val”。如果图中的“if”条件句成立将会调用代码中定义的“test_show_bytes()”函数。下面先分析条件成立的情况(即有参数的情况)。
(4)下面的代码将“val”赋值给“ival”并强制转换成浮点型并赋值给了“fval”。并接着调用了事先定义的“show_int()”“show_float()”“show_pointer()”函数,传递对应的参数。
(5)下面以“show_int()”为例,只是调用了先前定义的“show_bytes()”函数,并把对应的参数传递过去。
(6)首先这里的“size_t”相当于“unsigned int”。“for”循环将数据在机器中的存储地址和存储的数据依次一行行打出。“%p”地址的格式符,“\t”水平制表符,“%.2x”将数据以十六进制输出并占两格。
(7)接下来是“if”条件不满足的情况。最先调用的是已定义的“show_twocomp”函数。函数中定义了短整型变量“x”,赋值“12345”,并将“-x”赋值给“mx”,“-x”即为“~x+1”。
(8)而后调用的已定义函数“simple_show_a()”和“simple_show_b()”除了函数中定义的变量的初值不同,其余是一样的。以“simple_show_a()”为例。
先给定义的整型变量“val”赋一初值,并把其地址赋给“valp”。然后调用“show_bytes”函数。可以发现,三次调用仅传递的数字不一样,此数字决定了之后将打出数据在机器中存储位置的前几个。
(9)再接着调用的“float_eg()”函数,同样也实验了两次,使用了不同的数据。以第一次的实验为例。
首先定义了一整型变量“x”并赋初值,接着将其强制转换为浮点数“f”。
(10)再之后调用的“string_ueg()”和“string_leg()”。两函数仅定义的指向字符常量的指针的值大小写不同,操作都相同。
3.运行结果分析
注:在linux环境中运行
①命令行中不带参数
(如上图),在命令行中打“gcc show_bytes.c”对代码进行编译,在打“./a.out”看运行的结果。
show_twocomp,代码中“short x=12345”,化为十六进制为“0x3039”,化为二进制为“0011 0000 0011 1001”(短整型为十六位,两个字节)。“short mx=-x”,“mx”二进制为“1100 1111 1100 0111”,十六进制为“0xcfc7”。观察实验结果,可发现数据在机器中是按“小端”存放。
simple_show_a,代码中“int val = 0x87654321”。观察实验结果,为三段,分别是:数据在机器中存储的前一个地址及数据、前两个地址及数据、前三个地址及数据。数据为八位一组存放即十六进制的两个数一组。由结果可知数据在机器中按“小端”存放。
simple_show_b,代码中“int val = 0x12345678”,仅仅是赋初值与“simple_show_a”不同,其余操作皆相同。由结果可知数据在机器中按“小端”存放。
float_eg(),代码中先是“int x = 3490593”,“x”十六进制为“0x354321”,二进制为“0011 0101 0100 0011 0010 0001”,整型变量占三十二位,四个字节。强制转换为浮点型并赋值给“f”,“f”的二进制中“E”为21,有其二进制为“0 10010100 1010 1010 0001 1001 0000 100”共32位,化为十六进制为“0x4a550c84”。观察实验结果,数据在机器中按“小端”存放。接下来的代码只是改变了“x”的值,操作不变。“x=3510593”,其十六进制为“359141”,二进制为“0011 0101 1001 0001 0100 0001”。将其强制转换成浮点数赋给“f”,其二进制为“0 1001 0100 1010 1100 1000 1010 0000 100”,十六进制为“0x4a564504”(如下图)。
string_ueg(),指向字符常量的指针“s = “ABCDEF””,“A”–“F”的ASKII码值为65—70,十六进制为“0x414243444546”。
string_leg(),指向字符常量的指针“s = “abcdef””,“a”–“f”的ASKII码值为97—102,十六进制为“0x616263646566”。
②命令行中带参数
注:以1073741824为例
先输入命令“gcc show-bytes.c”编译,在输入“./a.out 1073741824”。
“int ival = val”,赋给整型时,“ival”的十六进制为“0x40000000”,二进制为“1000 0000 …”(共32位)(如上图)。
“double fval = (double) ival”,由实验结果可以发现在此系统中,double数据的位数和float一样为32位。“fval”的二进制为“0 1001 1110 0000 …”(共32位),其十六进制为“0x4f800000”(如上图)。
“int *pval = &ival”,由结果来看,指针变量的位数为64位(8个字节)(如上图)。