原码反码和补码,一篇就够了,全网最详细解析

本文详细介绍了计算机中整数的补码表示法,以及如何进行补码运算。通过两个实例说明了补码计算过程,解释了为何计算机中不存在原码和反码,以及byte类型取值范围从-128到127的原因。讨论了二进制数据的高位为1时代表负数,以及0的正负表示问题,强调了10000000表示-128的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

其实对于计算机来说,并不存在原码和反码,计算机存储的二进制数据都是以补码的形式存放的,自然对数据的运算也是直接用补码来运算(计算机中只有加法器没有减法器)

我们都知道正整数(包括0)的补码是它本身,负整数的补码是它的原码非符号位取反再加一

先来看个例子1:

十进制整数二进制原码二进制补码
701110111
-511011011

所以我们当计算机要计算7-5=?,实际上计算机直接认为是7+(-5)=?, 所以计算机把存储的7和-5对应的补码拿过来直接相加 0111+1011=0001 0010 ,我们看到数据溢出了,不过只要看后四位就行!我们要清楚计算所得的0010是直接存储在计算机中的!所以0010本质上来说是最终计算结果所对应二进制的补码(补码+补码=补码)。也就说我们要将0010这个补码逆推回所需要的原码,后四位0010的高位为0,显然是正数,那么0010这个补码对应的原码依然是0010!0010转换为十进制是2,7-5=2成立!

再来看个例子2:

十进制整数二进制原码二进制补码
70000 01110000 0111
-81000 10001111 1000

7-8=7+(-8)=? ---> 0000 0111 + 1111 1000=1111 1111 ,这次我们发现得到1111 1111 这个补码的高位是1,这就表明该补码对应的原码是一个负数。

对于负整数来说:补码=(原码)取反+1,那么原码=(补码-1)取反,注意取反时符号位不变!

1111 1111 -0000 0001=1111 1110 --->取反---> 1000 0001,很显然这个原码表示十进制的-1 ,7-8=-1成立!

关于byte整型的取值范围为(-128 ~ 127) 是为啥?

我们知道byte整型使用一个字节,也就是8位(bit)来表示二进制数据,那么直观的看应该是这样:

正数范围:   0000 0000 ~0111 1111

负数范围:   1000 0000 ~1111 1111

那么很显然 :

     0000 0000 表示+0 

     0111 1111  表示+127

那么 1000 0000难道表示 -0 ,1111 1111表示-127 ??? 那我们在取值范围看到的-128是哪来的???当然不是!!

首先我们来解释1000 0000为什么不能代表 -0, 准确的说是为什么不能有 -0的存在!

1000 0000不能表示 -0 的原因

在数学中我们知道0既不是正数也不是负数,但是在计算机中由于二进制数据的高位不是0就是1 ,也就是说不是正数就是负数,因此二进制只能把0归为正数或负数,而将0表示为0000 0000 是非常自然的!所以说规定0在二进制中其实是一个正数,也就是+0!那么当然就不允许有-0这种形式的出现了,计算机不可能将一个数据以两种形式存放,否则会导致混乱,那么为了让1000 0000 不被闲置,我们自然地想让它表示其余某一个数!那么表示什么数呢?这里我们先放一放

1111 1111不能表示-127的原因

这其实是初学者极其容易犯的毛病,之前讲过,对于计算机来说,并不存在原码和反码,计算机存储的二进制数据都是以补码的形式存放的,因此对于1111 1111这个二进制数据来说,如果我们要得到它的十进制数据是需要求其原码的,显然1111 1111的原码是-1才对!也就是说对于计算机来说1111 1111代表的就是-1。因此我们也可以容易的得到1000 0001表示的才是-127。其实更广义的说,不只是1000 0000 ,只要是所有多字节二进制数中,最高位为1 其余位都为0的二进制数据都使用人为表示的1个数,这个数在十进制中就是-2^n (n表示除符号位以外的其余位位数)

 例如2个字节的二进制数据1000 0000 0000 0000 表示-2^15=-32768 ;注意 如1000 0000 0000其实是0000 1000 0000 0000,所以它不是以为的-2^11,而是2^11

综上所述

0000 0000 ~0111 1111 表示  +0 ~ +127

1111 1111 ~1000 0001 表示   -1 ~  -127

咦,我们好像漏了 1000 0000 这个二进制了,哈哈,到现在为止一切都解决了,其实我们人为规定 1000 0000表示十进制中的-128!当然我们不可能说通过 1000 0000这种二进制求其原码得到某一个数,因为非高位全是0,无法再借位减1了!

其实这种规定是很自然的,1000 0000 -0000 0001=0111 1111,而0111 1111 这个补码表示的是+127,我们可以将 1000 0000这个二进制作为正数和负数之间的一个分水岭(尽管1000 0000本身代表负数),1000 0000再进位就会进入负数范围,若借位就会进入正数范围,就好似1000 0000(-128)将 1000 0001(-127) ~0111 1111(+127)首尾连接了起来形成了一个闭环!!!

讲到这里 所有的疑问就解决了,感谢你的观看!

<think>嗯,用户想了解C语言中的__attribute__关键字的使用说明示例。首先,我需要回忆一下关于这个关键字的用法。记得__attribute__是GCC的扩展特性,主要用于给编译器提供额外的信息,比如优化结构体对齐、函数行为等。 首先,我应该解释__attribute__的基本概念,说明它是GCC特有的,可能影响可移植性。然后,分点列出常用的属性,比如packed、aligned、deprecated、format等,每个都要给出示例代码,这样用户更容易理解。 比如packed属性,可以用于结构体,取消对齐填充。示例代码中,用户提供的引用[1]里有一个结构体的例子,可以直接引用过来。接着是aligned,设置对齐方式,引用[3]中的例子可以用来说明如何指定结构体或类型的对齐字节数。 然后是deprecated属性,标记过时的函数或变量,提醒开发者不要使用。还有format属性,用于函数参数的格式检查,引用[4]中的printf样式检查的例子很合适,需要说明参数的位置类型。 接下来,可能需要提到其他属性,比如unused,防止未使用变量的警告,以及section,将变量或函数放入指定段。这些也是常见的用法,但用户可能没有提到,需要补充。 注意事项部分,用户提供的引用[2]已经提到了可移植性问题、编译器依赖性性能影响,这些需要强调,确保用户知道潜在的问题。 用户的问题中还要求生成相关问题,我需要考虑用户可能进一步想知道的内容,比如不同编译器的替代方案、对齐对性能的影响、实际应用场景,以及如何检测过时API的使用。这些问题能帮助用户深入理解。 需要注意的是,用户提供的引用中有多个例子,要正确标注引用标记,比如[^1]、[^2]等,确保引用来源正确。同时,代码示例要符合C语法,避免错误。例如,结构体定义中的packed位置是否正确,是否需要typedef等。 后,确保回答结构清晰,分点说明,每个属性都有示例解释,同时注意事项部分要突出,让用户明白使用时的限制潜在问题。检查是否有遗漏的重要属性,或者是否有更常见的用法需要补充。例如,noreturn属性是否常用,是否需要提及?可能用户更关注基础用法,所以先集中在常用的几个属性上。</think>### C语言__attribute__关键字使用说明 `__attribute__`是GCC编译器特有的扩展特性,用于向编译器传递附加信息以优化代码或控制内存布局。以下是其常见用法及示例: --- #### 1. **内存对齐控制** - **`packed`属性**:取消结构体成员的内存对齐填充 ```c struct packed_struct __attribute__((packed)) { char a; // 1字节 int b; // 4字节(通常需要对齐到4字节边界,但packed取消对齐) }; // 总大小为5字节(默认编译环境可能为8字节) ``` 此属性常用于节省内存空间或处理网络协议数据包。 - **`aligned`属性**:强制指定对齐方式 ```c struct S __attribute__((aligned(8))) { short f[3]; // 每个short占2字节,共6字节 }; // 结构体按8字节对齐 typedef int more_aligned_int __attribute__((aligned(8))); // 类型强制8字节对齐 ``` 此属性适用于需要特定内存对齐的场景(如SIMD指令优化)[^3]。 --- #### 2. **函数行为控制** - **`deprecated`属性**:标记过时函数或变量 ```c void old_api() __attribute__((deprecated("改用new_api()"))); ``` 编译时会触发警告,提示开发者迁移到新接口[^2]。 - **`format`属性**:强制格式字符串检查 ```c void my_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); ``` 编译器会校验参数与格式字符串的匹配性(类似`printf`)[^4]。 --- #### 3. **其他常用属性** - **`unused`属性**:抑制未使用变量的警告 ```c int __attribute__((unused)) debug_flag; // 标记变量可能未被使用 ``` - **`section`属性**:指定代码/数据存放的段 ```c int var __attribute__((section(".custom_section"))); // 变量存入自定义段 ``` --- #### 注意事项 1. **可移植性**:`__attribute__`为GCC扩展,其他编译器(如MSVC)可能不支持[^2]。 2. **性能权衡**:过度使用对齐属性可能导致内存浪费或缓存不友好。 3. **语法限制**:属性需紧跟在声明后,多属性用逗号分隔:`__attribute__((aligned(8), packed))` ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值