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

news2024/11/25 13:01:01

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(截断)

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1986090.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android 自定义View(二):画布、画笔、路径(遮罩)以及Sufaceview

目录 1&#xff09;画布是什么&#xff1f;画布如何使用&#xff1f; 2&#xff09;画笔是什么&#xff0c;画笔如何生成呢&#xff1f; 3&#xff09;如何画圆、画文字、画矩形 4&#xff09;路径&#xff08;Path&#xff09;遮罩 5&#xff09;Sufaceview&#xff08;使用…

UWB实操:使用 litepoint 定制UWB信号,BPRF,HPRF,mean PRF,SFD,gap,PSDU,STS

使用 litepoint 定制UWB信号 预备知识: Technology选择UWBP VSG -> WaveGen ->UWBP Wave settings G

2024.8.6 作业

1> 使用消息队列完成两个进程之间相互通信 snd.c #include <myhead.h>struct msgbuf {long mtype;char mtext[1024]; };#define SIZE sizeof(struct msgbuf)-sizeof(long)int main(int argc,const char *argv[]) {pid_t pid fork();if(pid-1){perror("fork er…

【C++入门(下)】—— 我与C++的不解之缘(二)

前言 接上篇&#xff0c;继续来学习C&#xff0c;本篇内容大概有 引用&#xff0c;inline 和 nullptr。 六、引用&#xff1a; 6.1、引用的定义 引用不是新定义一个变量&#xff0c;而是给已存在的变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它…

SQL基础命令

目录 查看版本 root登录 查看用户 数据库清单 创建数据库 选择数据库 删除数据库 退出 MySQL 查看版本 mysql --version root登录 mysql -uroot -p 查看用户 select user()&#xff1b; 数据库清单 show databases; 创建数据库 # create database xxx; create dat…

heic格式批量转化jpg,这几个方法简单好上手!

在这个数字化时代&#xff0c;手机摄影已成为我们记录生活、分享美好的重要方式。然而&#xff0c;苹果用户可能会遇到一个头疼的问题——拍摄的照片默认保存为HEIC格式&#xff0c;这种格式虽然能大幅节省存储空间&#xff0c;但在非苹果设备上查看或编辑时却不太方便。别担心…

8月开始|660/880/严选题45天强化带刷计划

45天刷完《严选题》《660》《880》&#xff1f; 可能吗&#xff1f; 是不是又在制造焦虑&#xff1f; 别急&#xff0c;其实严选题《660》《880》的核心知识点并不多&#xff0c;45天完全能够刷完&#xff0c;下面就是帮大家整理总结的这些习题册的核心知识点和重点题&#…

【多线程-从零开始-肆】线程安全、加锁和死锁

进程状态 进程状态&#xff1a; 就绪&#xff1a;正在 CPU 上执行&#xff0c;或者随时可以去 CPU 上执行阻塞&#xff1a;暂时不能参与 CPU 的执行 Java 的线程&#xff0c;对应状态做了更详细的区分&#xff0c;不仅仅是就绪和阻塞了 六种状态&#xff1a; NEW 当前 Thread…

vulnhub靶机实战_DC-8

一、靶机下载 靶机下载链接汇总&#xff1a;https://download.vulnhub.com/使用搜索功能&#xff0c;搜索dc类型的靶机即可。本次实战使用的靶机是&#xff1a;DC-8系统&#xff1a;Debian下载链接&#xff1a;https://download.vulnhub.com/dc/DC-8.zip 二、靶机启动 下载完…

C++编程基础的学习

Qt跨平台特性 在深入探讨C编程的基础知识之前&#xff0c;我们首先需要了解Qt框架的跨平台特性。Qt是一个功能强大的跨平台应用程序框架&#xff0c;它允许开发者编写一次代码&#xff0c;然后在多个平台上运行&#xff0c;包括Windows、macOS、Linux、iOS、Android等。这种跨…

Linux网络编程3

并发服务器 1.TCP多进程并发服务器 服务器端&#xff1a; 客户端&#xff1a; 2.TCP多线程服务器 服务器端&#xff1a; 客户机端&#xff1a; 需要学习的函数还有 1. send() 函数 send() 函数用于在套接字上发送数据。它是网络编程中发送数据到对端的主要函数之一。 函数…

人像修图-高低频磨皮

原理 将图像分成高频图层&#xff08;处理纹理细节&#xff09;和低频图层&#xff08;处理光影和光影&#xff09;&#xff0c;以达到修饰时互不干扰 步骤 复制两个图层 在低频图层建立高斯模糊&#xff1a;滤镜->模糊->高斯模糊。注意半径一般根据皮肤占比&#xf…

day 20进程

一、程序和进程的区别 程序&#xff1a;保存在磁盘空间中的的一段代码的集合&#xff0c;死的 进程&#xff1a;是一个程序动态执行的过程&#xff0c;包括进程的创建、调度和消亡的过程 二、进程相关的命令 PID:进程的标识符(进程的ID) PPID:父进程的ID号 三、进程的创建…

redis的数据结构与对象

简单动态字符串 文章目录 简单动态字符串SDS的定义SDS的结构图示结构SDS字段解析SDS的特点 SDS和字符串的区别常数复杂度获取字符串的长度杜绝缓冲区的溢出减少修改字符串时的内存分配次数二进制安全兼容部分c字符串函数总结 链表链表和链表节点的实现链表节点&#xff08;list…

全球手机基站位置数据,包含(2G-5G)基站

OpenCellID 是一个由社区维护的项目&#xff0c;它提供了一个开放的数据集&#xff0c;包含全球各地的移动通信基站信息。这个项目对于需要获取蜂窝网络基础设施详细信息的研究人员、开发者以及组织来说非常有用。这些信息可以被用来进行各种分析和应用开发&#xff0c;例如改进…

Python 在开发中的设计模式有哪些?怎样使用?

大家好&#xff01;我是爱摸鱼的小鸿&#xff0c;关注我&#xff0c;收看每期的编程干货。 今天我们要聊点硬核的——设计模式。不过&#xff0c;不用担心&#xff0c;我会带着热情来跟你分享这些看似枯燥的知识点。让我们一起从“代码搬砖工”蜕变成“代码艺术家”吧&#xff…

Redis面试题大全

文章目录 Redis有哪几种基本类型Redis为什么快&#xff1f;为什么Redis6.0后改用多线程?什么是热key吗&#xff1f;热key问题怎么解决&#xff1f;什么是热Key&#xff1f;解决热Key问题的方法 什么是缓存击穿、缓存穿透、缓存雪崩&#xff1f;缓存击穿缓存穿透缓存雪崩 Redis…

python爬虫预备知识三-多进程

python实现多进程的方法&#xff1a;fork、multiprocessing模块创建多进程。 os.fork方法 os.fork方法只适合于unix/linux系统&#xff0c;不支持windows系统。 fork方法调用一次会返回两次&#xff0c;原因在于操作系统将当前进程&#xff08;父进程&#xff09;复制出一份…

ESP8266使用舵机以及16路PWM舵机PCA 9685的使用方式

PWM全称 50Hz也就是一秒内变换50次 根据上面的公式 一个高电平一个低电平叫一个脉冲。 例如每个脉冲占20毫秒&#xff0c;那么他的频率是多少&#xff1f; 就是用1去除以他的周期&#xff0c;也就是我们上面说的20&#xff0c;那么就是除0.02,1秒等于1000毫秒&#xff0c;20…

网络安全 - 应急响应检查表

前言 本项目旨在为应急响应提供全方位辅助&#xff0c;以便快速解决问题。结合自身经验和网络资料&#xff0c;形成检查清单&#xff0c;期待大家提供更多技巧&#xff0c;共同完善本项目。愿大家在应急之路一帆风顺。 图片皆来源于网络&#xff0c;如有侵权请联系删除。 一…