C语言中整数类型及其类型转换

1.数据的存储和排列

 是的,在C语言中,整数类型通常以补码(two's complement)形式存储在内存中。这是因为补码表示法在处理有符号整数的加减运算上更为简便和高效。

基本类型所占字节数:

大端方式存储

 就相当于我们平时的习惯,位权高的数写在最左端,例如:100 元。

内存地址0123
存储内容数据的最高有效字节数据的次高有效字节数据的次低有效字节数据的最低有效字节
以 0x12345678 为例子:
内存地址0123
存储内容0x120x340x560x78

小端方式存储

 位权低的数写在最左端,计算机内部存储数据最常用:

例如8086cpu的寄存器中所存数据:

该汇编语言是将1234H存入寄存器AX中在送进内存1000:0000处

 

可以看到1000:0000出存的是1234H的低位字节34H,1000:0001处存的是1234H的高位字节12H. 

内存地址0123
存储内容数据的最低最高有效字节数据的次低有效字节数据的次高有效字节数据的最高有效字节
以 0x12345678 为例子:
内存地址0123
存储内容0x780x560x340x12

边界对齐方式存储 

 

字节对齐是一种计算机内存存储数据的方式。

在计算机系统中,为了提高内存访问效率,数据通常按照特定的规则在内存中进行存储,这就是字节对齐。

其基本规则通常是:结构体或类中的成员变量,其存储地址应该是其自身大小的整数倍。例如,一个 4 字节大小的整数类型变量,通常会存储在地址能被 4 整除的内存位置。

字节对齐的主要目的有两个:一是提高 CPU 访问内存的效率,因为大多数计算机体系结构在访问对齐的数据时效率更高;二是便于不同硬件平台和编译器之间的数据交换和移植。

假设一个结构体包含一个 char 类型(1 字节)和一个 int 类型(4 字节)。如果没有字节对齐,char 类型之后紧接着存储 int 类型,可能导致 int 类型的存储地址不是 4 的倍数,从而在访问 int 类型数据时降低效率。但如果进行字节对齐,char 类型之后可能会填充若干字节,使得 int 类型从能被 4 整除的地址开始存储。

假设我们有这样一个结构体:

struct MyStruct {
    int num;  // 4 字节
    char ch;  // 1 字节
    short sh; // 2 字节
};

在大多数常见的编译器中,存储方式通常如下:

内存地址0123
存储内容int num 的低字节int num 的次低字节int num 的次高字节int num 的高字节
内存地址4567
存储内容char ch填充字节short sh 的低字节short sh 的高字节

首先存储 int 类型的 num,由于 int 通常是 4 字节对齐,所以 num 会从能被 4 整除的地址开始存储。

然后是 char 类型的 ch,它占用 1 字节。但为了满足后面 short 类型的 2 字节对齐要求,可能会在 ch 后面填充 1 字节。

最后是 short 类型的 sh,它从能被 2 整除的地址开始存储。

总的来说,字节对齐可能会导致结构体在内存中占用的空间比成员变量实际大小之和要大一些,这是为了提高内存访问效率。

 

2.有符号数和无符号数之间的转换

在C语言中,有符号数和无符号数之间的转换可以通过类型转换(type casting)实现。需要注意的是,这种转换会影响数值的解释。

有符号数转无符号数

将有符号数转换为无符号数时,二进制表示保持不变,但解释方式不同。

#include <stdio.h>

int main(){
	int signed_num = -1;
	unsigned int unsigned_num = (unsigned int)signed_num; // 0xFFFFFFFF
	printf("signed_num = %d, unsigned_num = %u\n", signed_num, unsigned_num);
	return 0;
} 

输出结果:

 

有符号数转无符号数在内存中的解释:

变量名内存地址二进制表示解释
signed_num0x7fffeeaee1011111111 11111111 11111111 11111111-1 (有符号数)
unsigned_num0x7fffeeaee1411111111 11111111 11111111 111111114294967295 (无符号数)

 可以看到二进制表示保持不变,只是改变了解释方式

无符号数转有符号数

将无符号数转换为有符号数时,同样二进制表示保持不变,但解释方式不同。

#include <stdio.h>

int main(){
	unsigned int unsigned_num = 4294967295; // 0xFFFFFFFF
	int signed_num = (int)unsigned_num; // -1
	printf("unsigned_num = %u, signed_num = %d\n", unsigned_num, signed_num);
	return 0;
} 

 输出结果:

 

无符号数转有符号数在内存中的解释:

变量名内存地址二进制表示解释
unsigned_num0x7fffeeaee1811111111 11111111 11111111 111111114294967295 (无符号数)
signed_num0x7fffeeaee1c11111111 11111111 11111111 11111111-1 (有符号数)

 可以看到二进制表示保持不变,只是改变了解释方式

3.不同字长整数之间的转换

在C语言中,不同字长的整数之间的转换主要涉及位宽扩展和截断操作。

从小字长向大字长扩展

对于有符号数,可以通过符号扩展实现扩展;对于无符号数,可以通过零扩展实现扩展。

#include <stdio.h>

int main(){
	char small_num = -1;
	int large_num = (int)small_num; // 符号扩展,小数到大数
	printf("small_num = %d, large_num = %d\n", small_num, large_num);

	unsigned char usmall_num = 255;
	unsigned int ularge_num = (unsigned int)usmall_num; // 零扩展
	printf("usmall_num = %u, ularge_num = %u\n", usmall_num, ularge_num);

	return 0;
} 

输出结果: 

 

从小字长向大字长扩展在内存中的解释:

变量名内存地址二进制表示解释
small_num0x7fffeeaee2011111111-1 (8位有符号数)
large_num0x7fffeeaee2411111111 11111111 11111111 11111111-1 (32位有符号数)
变量名内存地址二进制表示解释
usmall_num0x7fffeeaee2811111111255 (8位无符号数)
ularge_num0x7fffeeaee2c00000000 00000000 00000000 11111111255 (32位无符号数)

 对于有符号数,从小字长向大字长可以通过符号扩展实现扩展;

从大字长向小字长截断

当将大字长整数转换为小字长整数时,高位会被截断,只保留低位。

#include <stdio.h>

int main(){
	int large_num = 257; // 0x00000101
	char small_num = (char)large_num; // 0x01
	printf("large_num = %d, small_num = %d\n", large_num, small_num);

	unsigned int ularge_num = 65537; // 0x00010001
	unsigned char usmall_num = (unsigned char)ularge_num; // 0x01
	printf("ularge_num = %u, usmall_num = %u\n", ularge_num, usmall_num);


	return 0;
} 

 输出结果:

 大字长到小字长整数之间的转换在内存中的解释:

数据类型变量名内存地址示例二进制表示解释
intlarge_num2570x701000000000 00000000 00000001 00000001257
charsmall_num10x7000000000011(截断)
unsigned intularge_num655370x701400000000 00000001 00000000 0000000165537
unsigned charusmall_num10x7008000000011(截断)

可以看到 大字长到小字长整数之间的转换在是直接截去多余的高位,只保留对应得低位。

  • 30
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值