不同数据类型的内部秘密----编程内幕(2)

Q: char类型是如何被当成int处理的?

A:    我们可以看看char类型变量在何时才会被当做int处理.

#include <stdio.h>int main()
{char ch;ch = 'a';printf("%c\n", ch);return 0;
}


汇编代码如下:

hello`main:0x100000f60 <+0>:  pushq  %rbp0x100000f61 <+1>:  movq   %rsp, %rbp0x100000f64 <+4>:  subq   $0x10, %rsp0x100000f68 <+8>:  leaq   0x43(%rip), %rdi          ; "%c\n"0x100000f6f <+15>: movl   $0x0, -0x4(%rbp)
->  0x100000f76 <+22>: movb   $0x61, -0x5(%rbp)0x100000f7a <+26>: movsbl -0x5(%rbp), %esi0x100000f7e <+30>: movb   $0x0, %al0x100000f80 <+32>: callq  0x100000f92               ; symbol stub for: printf

movb $0x61, -0x5(%rbp)是把字符'a'保存到ch变量中. movb是单个字节的拷贝,显然此时ch并没有当做int来处理.

而在后面: movsbl -0x5(%rbp), %esi表明ch被放到了int大小的register中,说明ch被提升为int.

再看一个例子:

#include <stdio.h>int main()
{char ch;int i = 0xF;ch = 'a';i = i + ch;printf("%d\n", i);return 0;
}

hello`main:0x100000f40 <+0>:  pushq  %rbp0x100000f41 <+1>:  movq   %rsp, %rbp0x100000f44 <+4>:  subq   $0x10, %rsp0x100000f48 <+8>:  leaq   0x57(%rip), %rdi          ; "%d\n"0x100000f4f <+15>: movl   $0x0, -0x4(%rbp)0x100000f56 <+22>: movl   $0xf, -0xc(%rbp)0x100000f5d <+29>: movb   $0x61, -0x5(%rbp)
->  0x100000f61 <+33>: movl   -0xc(%rbp), %eax0x100000f64 <+36>: movsbl -0x5(%rbp), %ecx0x100000f68 <+40>: addl   %ecx, %eax0x100000f6a <+42>: movl   %eax, -0xc(%rbp)0x100000f6d <+45>: movl   -0xc(%rbp), %esi0x100000f70 <+48>: movb   $0x0, %al0x100000f72 <+50>: callq  0x100000f84               ; symbol stub for: printf

在执行i = i + ch: 

movsbl -0x5(%rbp), %ecx
addl   %ecx, %eax

此时,证明了char被提升为int.

由上面可见,char被提升为int是在char和int一起处理或者当参数传递时才会产生,如果char变量单独使用,又有什么必要提升为int呢?

 

Q: unsigned int和int究竟有何区别?

A: 

#include <stdio.h>int main()
{int i;unsigned int j;i = 1;j = 2;return 0;
}
hello`main:0x100000f90 <+0>:  pushq  %rbp0x100000f91 <+1>:  movq   %rsp, %rbp0x100000f94 <+4>:  xorl   %eax, %eax0x100000f96 <+6>:  movl   $0x0, -0x4(%rbp)
->  0x100000f9d <+13>: movl   $0x1, -0x8(%rbp)0x100000fa4 <+20>: movl   $0x2, -0xc(%rbp)0x100000fab <+27>: popq   %rbp0x100000fac <+28>: retq  

两条movl语句并没有太大区别,看起来int i和unsigned int j在cpu看来并没有什么区别,都是4字节,对应不同地址而已.

下面我们用int和unsigned int比较大小:

#include <stdio.h>int main()
{int i;unsigned int j;i = 1;j = -1;printf("%d\n", i > j);return 0;
}

    0x100000f56 <+22>: movl   $0x1, -0x8(%rbp)0x100000f5d <+29>: movl   $0xffffffff, -0xc(%rbp)   ; imm = 0xFFFFFFFF 0x100000f64 <+36>: movl   -0x8(%rbp), %eax0x100000f67 <+39>: cmpl   -0xc(%rbp), %eax
->  0x100000f6a <+42>: seta   %cl0x100000f6d <+45>: andb   $0x1, %cl0x100000f70 <+48>: movzbl %cl, %esi0x100000f73 <+51>: movb   $0x0, %al0x100000f75 <+53>: callq  0x100000f88               ; symbol stub for: printf

在断点在如上位置时,

(lldb) register read rflagsrflags = 0x0000000000000213

RFLAGS寄存器 b0: CF = 1,  b6: ZF = 0.

所以seta  %cl保存到cl寄存器的数值为0: 只有CF = 0, ZF = 0的时候cl才会是1.

注意: seta指令是对无符号数比较的结果. 这里是印证了int和unsigned int在一起操作会被提升成unsigned int.

所以最终printf输出的结果为0.

对此规则,可能有人会提出异议,但基于一个基本的准则: 两个数据操作,向数据更长不会丢失数值的方向去转换.

Q: 1左移32位是多少?

A: 

#include <stdio.h>int main()
{int i = 1;int j;j = i << 32;printf("%d\n", j);return 0;
}
    0x100000f5f <+15>: movl   $0x20, %ecx0x100000f64 <+20>: movl   $0x0, -0x4(%rbp)0x100000f6b <+27>: movl   $0x1, -0x8(%rbp)0x100000f72 <+34>: movl   -0x8(%rbp), %eax0x100000f75 <+37>: shll   %cl, %eax0x100000f77 <+39>: movl   %eax, -0xc(%rbp)
->  0x100000f7a <+42>: movl   -0xc(%rbp), %esi0x100000f7d <+45>: movb   $0x0, %al0x100000f7f <+47>: callq  0x100000f92               ; symbol stub for: printf

可以看到shll左移%cl: 0x20即32位. 有一部分书籍说,左移语句对于超过数据大小比特长度会采用模比特长度的方式得到最终左移的位数,并认为这是编译器的行为. 其实不然,这是指令集的行为.

如下为Intel指令集手册的原文:

Shifts the bits in the first operand (destination operand) to the left or right 
by the number of bits specified in the second operand (count operand). Bits shifted 
beyond the destination operand boundary are first shifted into the CF flag, then 
discarded. At the end of the shift operation, the CF flag contains the last bit
shifted out of the destination operand.
The destination operand can be a register or a memory location. The count operand 
can be an immediate value or the CL register. The count is masked to 5 bits 
(or 6 bits if in 64-bit mode and REX.W is used). The count range is limited to 0 to 31
(or 63 if 64-bit mode and REX.W is used). A special opcode encoding is provided for a count of 1.


微风不燥,阳光正好,你就像风一样经过这里,愿你停留的片刻温暖舒心。

我是程序员小迷(致力于C、C++、Java、Kotlin、Android、Shell、JavaScript、TypeScript、Python等编程技术的技巧经验分享),若作品对您有帮助,请关注、分享、点赞、收藏、在看、喜欢,您的支持是我们为您提供帮助的最大动力。

欢迎关注。助您在编程路上越走越好!

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

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

相关文章

修改了环境变量~/.bashrc后 报错 命令 “dirname” 可在以下位置找到 * /bin/dirname * /usr/bin/dirname

问题如下&#xff1a; 修改了~/.bashrc后加入了环境变量之后报错&#xff0c;如下所示 (base) jiedell:~/桌面$ source ~/.bashrc 命令 “dirname” 可在以下位置找到 * /bin/dirname * /usr/bin/dirname 由于 /usr/bin:/bin 不在 PATH 环境变量中&#xff0c;故无法找到该…

在Linux上安装并启动Redis

目录 安装gcc环境 上传redis文件方法一&#xff1a;sftp 上传redis文件方法二&#xff1a;wget 启动redis-server ctrlc关闭redis-server 参考文章&#xff1a;Linux 安装 Redis 及踩坑 - 敲代码的阿磊 - 博客园 (cnblogs.com) 准备&#xff1a;打开VMware Workstation&am…

pair对组创建

创建方式1: pair<type,type> p(value1,value2); pair<string, int> p("Tom", 20); cout << "name:" << p.first << "age:" << p.second << endl; 创建方式2: pair<type,type> pmake_pair(v…

mysql权限分类

USAGE --无权限,只有登录数据库,只可以使用test或test_*数据库 ALL --所有权限 select/update/delete/super/slave/reload --指定的权限 with grant option --允许把自己的权限授予其它用户(此用户拥有建立账号的权限) 权限级别&#xff1a; 1、. &#xff0d;&#xff0d;全…

C语法:for循环执行顺序

今天下编写代码时遇到了如下情况&#xff1a;期望是输出 i1,j2 i1,j3 i1,j4 i2,j3 int main(void) {int i,j;for(i1;i<3;i){for(j1;j!i&&j<4;j){printf("i%d,j%d\n",i,j);}}return 0; }实际输出结果&#xff1a; i2,j1 分析上述代码&#xff1a…

商务分析方法与工具(九):Python的趣味快捷-Pandas处理公司财务数据集思路

Tips&#xff1a;"分享是快乐的源泉&#x1f4a7;&#xff0c;在我的博客里&#xff0c;不仅有知识的海洋&#x1f30a;&#xff0c;还有满满的正能量加持&#x1f4aa;&#xff0c;快来和我一起分享这份快乐吧&#x1f60a;&#xff01; 喜欢我的博客的话&#xff0c;记得…

LangChain:大模型框架的深度解析与应用探索

在数字化的时代浪潮中&#xff0c;人工智能技术正以前所未有的速度蓬勃发展&#xff0c;而大模型作为其中的翘楚&#xff0c;以生成式对话技术逐渐成为推动行业乃至整个社会进步的核心力量。再往近一点来说&#xff0c;在公司&#xff0c;不少产品都戴上了人工智能的帽子&#…

初识C语言——第十八天

循环while/do while while 语法结构 while(表达式) 循环语句; break:在while循环中&#xff0c;break用于永久的终止循环 continue:在while循环中&#xff0c;continue的作用是跳过本次循环continue后面的代码 直接去判断部分&#xff0c;看是否进行下一次循环。 注意事项…

Logstash详解

Logstash详解&#xff1a;构建强大日志收集与处理管道的利器 一、引言 在大数据和云计算的时代&#xff0c;日志数据作为企业运营和故障排查的重要依据&#xff0c;其收集、处理和分析能力显得尤为重要。Logstash&#xff0c;作为一款强大的日志收集、处理和转发工具&#xf…

[AI OpenAI-doc] 安全最佳实践

使用我们的免费 Moderation API OpenAI 的 Moderation API 是免费使用的&#xff0c;可以帮助减少您完成中不安全内容的频率。或者&#xff0c;您可能希望开发自己的内容过滤系统&#xff0c;以适应您的使用情况。 对抗性测试 我们建议对您的应用进行“红队测试”&#xff0…

即插即用篇 | YOLOv8引入轴向注意力 Axial Attention | 多维变换器中的轴向注意力

本改进已集成到 YOLOv8-Magic 框架。 我们提出了Axial Transformers,这是一个基于自注意力的自回归模型,用于图像和其他组织为高维张量的数据。现有的自回归模型要么因高维数据的计算资源需求过大而受到限制,要么为了减少资源需求而在分布表达性或实现的便捷性上做出妥协。相…

解决wangEditor使用keep-alive缓存后,调用editor.cmd.do()失败

前提&#xff1a;wangeditor版本&#xff1a;4.7.11 vue版本&#xff1a;vue2 问题&#xff1a;在使用wangeditor富文本编辑器时&#xff0c;需求需要通过点击一个按钮&#xff0c;手动插入定义好的内容&#xff0c;所以使用了 editor.cmd.do(insertHTML, ....) 方法新增…

青少年软件编程(Python)等级考试试卷(二级)2024年3月

2024.03电子学会青少年软件编程 Python二级 等级考试试卷 一、单选题 1.期末考试结束了&#xff0c;全班的语文成绩都储存在列表score 中&#xff0c;班主任老师请小明找到全班最高分&#xff0c;小明准备用Python 来完成&#xff0c;以下哪个选项&#xff0c;可以获取最高分…

较难题 链表的回文结构

本题来自链表的回文结构_牛客题霸_牛客网 (nowcoder.com) 234. 回文链表 - 力扣&#xff08;LeetCode&#xff09; 题面&#xff1a; 对于一个链表&#xff0c;请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法&#xff0c;判断其是否为回文结构。 给定一个链表的头…

03.Linux文件操作

1.操作系统与Linux io框架 1.1 io与操作系统 1.1.1 io概念 io 描述的是硬件设备之间的数据交互&#xff0c;分为输⼊ (input) 与输出 (output)。 输⼊&#xff1a;应⽤程序从其他设备获取数据 (read) 暂存到内存设备中&#xff1b;输出&#xff1a;应⽤程序将内存暂存的数据…

FANUC机器人基本保养概述

对于工业机器人来说&#xff0c;定期保养机器人可以延长机器人的使用寿命。对于FANUC机器人来说&#xff0c;FANUC机器人的常规保养周期可以分为日常、三个月、六个月、一年、两年、三年。以下是FANUC机器人的基本保养周期概览&#xff1a; 在实际生产应用中&#xff0c;可以参…

具身智能论文

目录 1. PoSE: Suppressing Perceptual Noise in Embodied Agents for Enhanced Semantic Navigation2. Embodied Intelligence: Bionic Robot Controller Integrating Environment Perception, Autonomous Planning, and Motion Control3. Can an Embodied Agent Find Your “…

7.STL_string(详细)

1. 什么是STL STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且 是一个包罗数据结构与算法的软件框架。 2. STL的版本 原始版本 Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版…

maven远程仓库访问顺序

首先需要了解一下各个配置文件&#xff0c;主要分为三类&#xff1a; 全局配置文件(${maven.home}/conf/settings.xml)&#xff0c;maven安装路径下的/conf/settings.xml用户配置文件(%USER_HOME%/.m2/settings.xml)&#xff0c;windows用户文件夹下项目配置文件&#xff1a;p…

C/C++ 入门(10)list类(STL)

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;C 欢迎来指教&#xff01; 目录 一、标准库中的list 1、了解 2、常用接口说明 a.常见的构造函数 b.迭代器 c. Capacity​编辑 d.Element access e.Modifiers 二、实现 1、框架 a.节点 b.迭代器 …