C学习:一个负数补码把我整蒙了

  • 负数补码实质
  • 代码示例分析
  • 问题来源
  • 问题分析

附:C代码在线调试工具

负数补码实质


负数补码定义参考之前讨论的一篇博客:C学习:有符号数类型的负数在计算机中的存储

正数的补码为其本身,负数的补码求取方式有两种。

方法一,人工求取步骤如下:

  • 取绝对值,得对应正数
  • 对正数的二进制形式按位取反
  • 将上面结果加1,得到补码

方法二,从原码角度来操作,如-32,求取步骤如下:

  • 原码为:10100000
  • 最高位不变,其余取反:11011111
  • 加一得补码:11100000

方法一过程为负数取绝对值,按位取反,再加1。方法二过程为原码的最高位不变,其余取反,然后加一。本质与方法一步骤一样,建议只用记第一种策略就行。

重要提示就是负数补码本质,计算机存负数时本身就已自动转换成补码,不需要单独再去转换。但是,如果不清楚的话,会仍在计算机存储后负数后继续对该变量人工求补码,这样就会出问题了。

再次强调下,负数在计算机里存储时,如 int num = -1; num本质已被转化成补码了,要想拿到补码,直接强制转成无符号数表达,其二进制就是补码。不信可以print以下步骤看看。

代码示例分析


假设输入num = -10,取消注释即可debug。

if (num < 0) {                    // 人工转换求取负数的补码// 逐步debug发现,取反位操作后,与预期不符,说明是在对本身负数存的补码在操作// int val = (int)num;        // 强制转成32位的// printf("0x%x\n", val);      // 0xfffffff6// val = -val;            // 符号位变正// printf("0x%x\n", val);     // 0xa// val = ~val;           // 负数的模,除符号位外按位取反// printf("0x%x\n", val);     // 0xfffffff5// val = val & 0x7FFFFFFF;    // 把符号位变成正// printf("0x%x\n", val);   // 0x7ffffff5// val = val + 1;            // 加1成补码,当正数处理// printf("0x%x\n", val);    // 0x7ffffff6// num = val;                 // 此步结果,不是正确的补码值// 负数本质在计算机里已被转化成补码了,要想拿到补码,直接强制转成无符号数表达,其二进制就是补码unsigned int val = (unsigned int)num;// printf("0x%x\n", val);     // 0xfffffff6, 补码时符号位一直为1,其他位则是在正数模的基础上取反加1num = val;  // 赋给num做正数处理
}

问题来源


该问题来自一个题目解答时遇到,题目描述为:将一个输入仅为数字的字符串,根据大小端顺序,分别将值用4字节打印出来。

问题分析


思路分析如下:

  1. 先字符串转换成数字,大于范围的直接返回overflow
  2. 范围内的,先判别是否有负号
  3. 正数按16转进制成字符,小端时每隔两个交换

实现代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>#define MAX_STR_LEN 512
// TestCase
// 1234567890123456789012345678900
// 4027691818
// -10
// 0
// 2^32 = 4294967296     || 减1
// -2^31 = -2147483648   || 减1
void GetHexString(const char *inputStr, char *output, int outputSize)
{long long num = atoll(inputStr); // long 和 int 实际范围一致,必须要用atollchar overFlow[] = "overflow";char *p = overFlow;char *p1 = output;char bigOrder[9] = "00000000";  // 含\0char litOrder[9] = "00000000";  // 默认应该都是0,而非FFFFFF...int modVal = 0;if (num < -1 * (long long)pow(2, 31) || num >= (long long)pow(2, 32)) { // 题目要求的范围,跟INT_MIN,INT_MAX还不太一致while (*p) { // 输出overflow*p1 = *p;p1++;p++;}*p1 = '\0';return;}p1 = &bigOrder[7];char *p2 = &litOrder[0];if (num < 0) { // 小于0,用补码,只要求到32位// 易错点unsigned int val = (unsigned int)num;num = val;  // 赋给num做正数处理}// 直接除以16,得到每个值,然后用字节序连起来// 注意大于0时,num不能用int或long表达,因为它只能存到2^31-1,题目要求表达到2^32while (num > 0) {      // 若num为0,则跳过modVal = num % 16; // 默认小端序先存着if (modVal >= 10) {*p1 = (modVal - 10) + 'A';*p2 = *p1;p1--;p2++;} else {*p1 = modVal + '0';*p2 = *p1;p1--;p2++;}num /= 16;}// 小端每两个内部交换位置int i = 0;for (i = 0; i < 8; i += 2) {char tmp = litOrder[i];litOrder[i] = litOrder[i + 1];litOrder[i + 1] = tmp;}// 连接大小端p1 = output;p = bigOrder;while (*p) {*p1 = *p;p++;p1++;*p1++ = *p++;*p1 = ' ';p1++;}*p1++ = '\n';p = litOrder;while (*p) {*p1 = *p;p++;p1++;*p1++ = *p++;*p1 = ' ';p1++;}*p1 = '\0';return;
}int main(void)
{char inputStr[MAX_STR_LEN];if (scanf_s("%s", inputStr, MAX_STR_LEN) != 1) { return -1; }char output[MAX_STR_LEN];GetHexString(inputStr, output, MAX_STR_LEN);printf("%s", output);while (1) { ; }return 0;
}

C学习:一个负数补码把我整蒙了相关推荐

  1. C语言中负数补码的方法,c语言里求负数补码的总结不足与优点.docx

    c语言里求负数补码的总结不足与优点 看C语言编码转换--------负数的二进制表示方法 XX-09-0710:49:17|分类:|标签:|举报|字号订阅 今天在看C语言编码转换时,既然对负数的二进制 ...

  2. 负数补码表示范围以及规格化数

    以小数为例 原码形式下 想象出一个数轴 ------------------------0------------------> 将0用原码表示,设机器字长为5,一位符号位,放在数轴上 ---- ...

  3. 时间序列学习(6):单整、协整、格兰杰检验

    时间序列学习(6):单整.协整.格兰杰检验 1.单整序列 2.协整关系 3.模型解释与协整检验 4.华泰柏瑞300与兴全300究竟能否搬砖? 前面的笔记里,我们都是在研究一个时间序列(不同时间段)中的 ...

  4. 负数 补码 原码

    负数在计算机中是用补码的形式存储的,正数在计算机中是用原码的形式存储的. 正数求原码直接将十进制转二进制即可,负数的补码是在原码的基础上除符号位外其余位取反后+1. 但是用这种方式求负数补码用编程实现 ...

  5. Java黑皮书课后题第7章:7.4(分析成绩)编写一个程序,读入个数不确定的考试分数,并且判断有多少个分数是大于或等于平均分,多少个分数是低于平均分的。输入一个负数表示输入结束。假设最高分是100

    7.4(分析成绩)编写一个程序,读入个数不确定的考试分数,并且判断有多少个分数是大于或等于平均分,多少个分数是低于平均分的.输入一个负数表示输入结束.假设最高分是100 题目 题目描述 破题 代码 运 ...

  6. # 自定义异常类 问题: 请使用代码实现 每一个学生(Student)都有学号,姓名和分数,分数永远不能为负数 如果老师给学生赋值一个负数,抛出一个自定异常

    自定义异常类 问题: 请使用代码实现 每一个学生(Student)都有学号,姓名和分数,分数永远不能为负数 如果老师给学生赋值一个负数,抛出一个自定异常 public class NoScoreExc ...

  7. 为什么 Web 开发人员需要学习一个 JavaScript 框架?

    原文链接 可能当我们结束本文时,一个新的 Javascript 框架已经在某处启动了.但这确实不在我们的控制范围内.因此,我们应该简单地继续我们所拥有的.至少,由于免责声明,我们可以确定我们不是在发明 ...

  8. C语言学习一个月后感想

    C语言学习一个月后感想 感谢李晓东老板及计算机工程师联盟的学长学姐和某神秘同级同学的辛勤指导,感谢宋雨田的督促和陪伴. 初识C的1..体会 我本以为凭借瓜皮思维和花里胡哨操作可以让我熟练地学习语言,现 ...

  9. linux学习一个服务(未完)

    学习一个服务的过程 1.了解服务的作用:名字 功能,特点 2.安装 3.配置文件位置,端口 4.服务启动关闭的脚本 5.此服务的使用方法 6.修改配置文件,实战举例 7.排错(从下到上,从内到外) 转 ...

最新文章

  1. 硬核吃瓜!上万条数据撕开微博热搜真相
  2. 信息学奥赛C++语言:新三好学生
  3. 1999元的AirPods Pro无线耳机突然发布,史上最大升级,买不买?
  4. MyBatis之基于XML的动态SQL
  5. 麻省、北大、清华等顶尖高校与企业 20 位强化学习专家齐聚,RLChina 2021 强化学习暑期课免费报名啦!...
  6. React Native开发之IDE(Atom+Nuclide)安装,运行,调试
  7. Myeclipse2014中,新建部署Maven项目
  8. 【C++】算法集锦(11):敏感词过滤算法(DFA)
  9. matlab中英文文献,matlab外文文献
  10. 如何在IDEA中使用 Jclasslib
  11. Linux环境下命令行下载DM8
  12. js自执行函数(function(){})()前加个分号是什么意思?
  13. 提高睡眠质量的东西,睡眠不好一定不要错过这几样东西
  14. win10更新安装会卡在44%怎么办
  15. WinX教程之我的实战(三)
  16. 一步步写嵌入式操作系统 arm相关知识
  17. python爬虫企业数据_python爬取企业名录并入库
  18. 一分钟让你明白OKR考核
  19. Problem 2261 浪里个浪(多起点与多终点问题)
  20. 网络营销推广怎么做 自媒体如何让商品消失不见

热门文章

  1. Python 告诉你绝不知道的1983-2018 春晚
  2. linux 远程文件拷贝
  3. 借x-emas-gw-sign解密,讲讲常见加密
  4. 开发linux学习板子_linux嵌入式开发板推荐,资深程序员教给你
  5. 超硬核,拒绝内卷全靠阿里大能整理的这份 Java 核心手册,堪称强无敌,谁来不说一声牛 AC
  6. mysql blackhole缺点_【MySql】 BlackHole :黑洞引擎-阿里云开发者社区
  7. Python操作MySQL数据库实现数据导入
  8. 在微信开发者工具使用eCharts
  9. VC++字符串转16进制字符串(附源码)
  10. 绑定非本机地址与透明代理