计算机基础

信息的表示

2.1.1 十六进制表示法

1) 对应表

十进制十六机制二进制
111
2210
3311
44100
55101
66110
77111
881000
991001
10A1010
11B1011
12C1100
13D1101
14E1110
15F1111

2)i + 4j形式

n的m次方的n进制就是1后面m个0 例如:2的5次方的二进制就是1后面5个0: 100000, 16的2次方的16进制就是1后面2个0: 100

2048=2^11

11=4*2+ 3(2的3次方后面2个0)

所以 16进制形式为 800

2.1.1 字

每台计算机都有一个字长(word size),指明整数和指针数据的标称大小。

2.1.3数据大小

C声明32位机器64位机器
char11
short int22
int44
long int48
long long int88
char*48
float44
double88

2.1.4寻址和字节顺序

#include <stdio.h>
typedef unsigned char * byte_pointer; // 定义数据类型 char*指针

/**
*以16进制的形式输出字节序列(计算机中的数据都可以看做字节序列)
*@start 字节序列的首个字节的地址
*@len 字节序列的长度
*/
void show_bytes(byte_pointer start, int len){
	int i;
	for(i = 0; i < len; i++){
		printf("%.2x ", start[i]); // 以16进制的形式(至少2个16进制位,2个16进制为刚好可以表示一个字节)输出当前字节
	}
	printf("\n");
}
/**
*输出int类型数字的字节序列(大端序和小端序刚好相反)
*/
void show_int(int val){
	show_bytes((byte_pointer)&val, sizeof(int));
}
void show_float(float val){
	show_bytes((byte_pointer)&val, sizeof(float));
}
void show_pointer(void* val){
	show_bytes((byte_pointer)&val, sizeof(void *));
}
int main(int argc, char* argv[]){

	show_int(12345); // 39 30 00 00 (linux64输出的是小端序), 实际16进制是 00 00 30 39

	int val = 0x87654321;
	byte_pointer valp = (byte_pointer)&val;
	show_bytes(valp, 1); // 21(linxu64,说明是小端序)
	show_bytes(valp, 2); // 21 43
	show_bytes(valp, 3); // 21 43 65
    float b = 12345.0;
	show_bytes((byte_pointer)&b, 4); // 00 e4 40 46 ,实际是 46 40 e4 00
	return 0;
}
#include <stdio.h>

/**
* 
*字节序列的二进制表示(小端序操作系统)
*@start 第一个字节的地址
*@len 字节序列的长度 
*/
void show_small_endpoint_bin(char * start, int len){

    unsigned char c;
    unsigned int n; // 无符号,右移运算只能是逻辑右移,左端补0;有符号数,右移运算会采用算术右移,左端补1
	char * p = start;
	for(int i = len-1; i >= 0; i--){ // 如 int 占4个字节,因为是小端序,所以倒过来输出
			c = p[i];
        	n = 0x80; // 1000 0000 = 0x80;
			for(int j = 0; j < 8; j++){ // 1个字节8个位
				
				if (c & n){
					printf("1");
				}else {
					printf("0");
				}
				if(j == 3){
					printf("-");
				}
				n >>= 1;
			}
			printf(" ");
	}
	printf("\n");
}
int main(int argc, char* argv[]){

	unsigned int a = 12345;  
	float b = 12345.0; 
	show_small_endpoint_bin((char*)&a, sizeof(unsigned int)); // 编码后计算机内部存放:  0x3930 0000    0000-0000 0000-0000 0011-0000 0011-1001
	show_small_endpoint_bin((char*)&b, sizeof(float)); // 编码后计算机内部存放:0x4640e400    0100-0110 0100-0000 1110-0100 0000-0000 
	return 0;
}

2.1.5 表示字符串

C语言中字符串被编码位一个以null(0)字符结尾的字符数组。

#include <stdio.h>
#include <string.h>
typedef unsigned char * byte_pointer; // 定义数据类型 char*指针

/**
*以16进制的形式输出字节序列(计算机中的数据都可以看做字节序列)
*@start 字节序列的首个字节的地址
*@len 字节序列的长度
*/
void show_bytes(byte_pointer start, int len){
	int i;
	for(i = 0; i < len; i++){
		printf("%.2x ", start[i]); // 以16进制的形式(至少2个16进制位,2个16进制为刚好可以表示一个字节)输出当前字节
	}
	printf("\n");
}

int main(int argc, char* argv[]){
    const char * s = "abcdef";
    show_bytes((byte_pointer)s, strlen(s)); //61 62 63 64 65 66 
	return 0;
}

2.1.6 表示代码

考虑下面的C函数:

int sum(int x, int y){
	reurn x + y;
}

当我们在示例机器上编译时,生成的机器码不同。

  • Linxu32: 55 89 e5 8b 45 0c 03 45 08 c9 c3
  • Windows: 55 89 e5 8b 45 0c 03 45 08 5d c3
  • Sun: 81 c3 e0 08 90 02 00 89
  • Linux64: 55 48 89 e5 89 7d fc 89 75 f8 03 45 fc c9 c3

2.1.7 布尔代数简介

与 或 非 异或

2.1.8 C语言中的位级运算

转成二进制按位做与 或 非 异或 运算。

位级运算的一个常见例子就是掩码运算。 如掩码 0xFF 表示低8位全是1, 一个整数x=0x89abcdef 与 0xFF做与运算可得到x的低8位,其他位则全是0;

2.1.9 C语言中的逻辑运算

C语言还提供了一组逻辑运算符 ||、&&、!分别对应命题逻辑中的OR、AND、NOT运算。 逻辑运算很容易和位运算相混淆,但它们的功能是完全不同的。逻辑运算认为所有非0的参数 都表示TRUE,而参数0表示FALSE。它们返回1或者0,分别表示TRUE或者FALSE。

2.1.10 C语言中的位移运算

C语言还提供了一组位移运算,以便向左或者向右移动位模式。

  • 左移(<<)k位:丢弃最高k位,并在右端补k个0;
  • 逻辑右移(>>)k位: 左端补k个0;
  • 算术右移(>>)k位: 左端补k个最高有效位的值。
操作值1值2
参数x0110 00111001 0101
x<<400xx 00000101 0000
x>>4(逻辑右移)0000 01100000 1001
x>>4(算术右移)0000 01101111 1001

C语言标准并没有明确定义应该使用哪种右移。对于无符号数据,右移必须是逻辑的。 而对于有符号数据算术的或逻辑的都可以。然而实际上,几乎所有的编译器都对有符号数据使用算术右移, 且许多程序员也都假设机器会使用这种右移动。

另一方面,java对进行右移有明确的定义,>> 做算术右移, >>>做逻辑右移。

关于作者

程序员,软件工程师,java, golang, rust, c, python,vue, Springboot, mybatis, mysql,elasticsearch, docker, maven, gcc, linux, ubuntu, centos, axum,llm, paddlepaddle, onlyoffice,minio,银河麒麟,中科方德,rpm