学习日志:show-bytes.c 程序分析


注:此篇文章废话较多

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个字节)(如上图)。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值