请考虑以下代码:
0.1 + 0.2 == 0.3 -> false
Run Code Online (Sandbox Code Playgroud)
0.1 + 0.2 -> 0.30000000000000004
Run Code Online (Sandbox Code Playgroud)
为什么会出现这些不准确之处?
我对汇编语言编程非常陌生,我目前正在尝试阅读从二进制文件生成的汇编语言.我跑过去了
test %eax,%eax
Run Code Online (Sandbox Code Playgroud)
或者test %rdi, %rdi等等.我很困惑这是做什么的.这些价值不%eax, %eax一样吗?什么是测试?我在某处读到它正在进行AND操作.....但由于它们是相同的值,它不会只返回%eax吗?
以下是我发现此用法的一个实例:
400e6e: 85 c0 test %eax,%eax
400e70: 74 05 je 400e77 <phase_1+0x23>
Run Code Online (Sandbox Code Playgroud)
je如果被比较的两个值相等,我认为跳跃......好吧,因为 %eax很好,本身,在什么情况下我们不会跳?
我是一般的编程初学者,所以如果有人能向我解释这一点,我会非常感激.谢谢!
我正在阅读Agner Fog的" 用C++优化软件 "(特定于英特尔,AMD和威盛的x86处理器),它在第34页说明
布尔变量存储为8位整数,值0表示false,1表示true.布尔变量是超定的,因为所有具有布尔变量作为输入的运算符检查输入是否具有除0或1之外的任何其他值,但是具有布尔值作为输出的运算符不能产生除0或1之外的其他值.布尔变量作为输入效率低于必要的效率.
这今天仍然适用于编译器吗?你能举个例子吗?作者说
如果确定操作数没有除0和1之外的其他值,则可以使布尔运算更有效.编译器没有做出这样的假设的原因是变量可能具有其他值,如果它们是未初始化或来自不明来源.
这是否意味着如果我拿一个函数指针bool(*)()作为示例并调用它,那么对它的操作会产生效率低下的代码?或者是通过取消引用指针或从引用读取然后对其进行操作来访问布尔值的情况?
我正在查看一些小的汇编代码,我无法理解TEST指令及其用法.我在循环结束时查看以下代码:
8048531: 84 c0 test al,al
8048533: 75 dc jne 8048511 <function+0x2d>
Run Code Online (Sandbox Code Playgroud)
我理解TEST的方式是它有点像AND运算符,它设置了一些标志.我想我真的不明白旗帜是如何运作的.test al,al对我来说,它看起来像检查相同的低位,并将始终得到相同的结果.
谁能解释一下?
某些CPU(特别是x86 CPU)在其状态寄存器中具有奇偶校验标志.该标志指示操作结果的位数是奇数还是偶数.
奇偶校验标志在编程环境中起什么实际用途?
旁注: 我假设它打算与奇偶校验位一起使用以执行基本的错误检查,但是这样的任务似乎并不常见,以保证整个CPU标志.
使用以下代码是否存在任何执行速度差异:
cmp al, 0
je done
Run Code Online (Sandbox Code Playgroud)
以下内容:
or al, al
jz done
Run Code Online (Sandbox Code Playgroud)
我知道JE和JZ指令是相同的,并且使用OR可以提供一个字节的大小改进.但是,我也关心代码速度.逻辑运算符似乎比SUB或CMP更快,但我只是想确定.这可能是规模和速度之间的权衡,或双赢(当然代码将更加不透明).
我是x86汇编语言的新手,我有一个保存在寄存器中的有符号整数eax,我想检查数字是负数还是正数.为此,我用bt指令检查第一位.
这是我做的:
bt eax,0
jnc isNegative
Run Code Online (Sandbox Code Playgroud)
bt第一位携带标志,我用来jnc检查进位标志是0还是1.如果是1,它应该是负数,并做负指令...但是,输出是不可预测的,有时我有一个积极的,它认为它是一个负数.难道我做错了什么?
编辑:我刚刚意识到它可能与endianess有关.它实际上是检查最后一位而不是第一位.让我试试吧bt,7
(ia32)例如,
test $eax, $eax
Run Code Online (Sandbox Code Playgroud)
你为什么要这么做?它呢$eax & $eax,对吧?这不应该总是设置标志寄存器说它们是相等的吗?
附录: 如果寄存器为零,那么测试将设置ZF(如下所述).那么测试(如上所述)主要用于判断寄存器是否为空?和ZF如果是这样的话?
这是一些C,在我正在学习的教科书中找到:
...
do {
...
n--;
} while (n > 0)
...
Run Code Online (Sandbox Code Playgroud)
我假设n是在%edx.
生成的汇编代码是:
testl %edx, %edx
jle .L5
Run Code Online (Sandbox Code Playgroud)
我明白jle测试小于或等于(SF ^ OF) | ZF.但是我不确定这条指令是如何对应的n > 0.有谁能解释一下?
昨天我看了VC++ 2010生成的一些32位代码(很可能;不知道具体的选项,对不起),我对一个奇怪的反复出现的细节很感兴趣:在许多功能中,它ebx在序言中归零,它总是像"零寄存器"一样使用它(想想$zeroMIPS).特别是,经常:
mov mem,imm大于1到4个字节mov mem,reg(即使对于0也必须编码完整的立即值大小),但通常(gcc)必要的寄存器被"按需"清零,并保持不变为了更有用的目的;cmp reg,ebx.这就是让我感到非常不寻常的事情,因为它应该完全相同test reg,reg,但是增加了对额外寄存器的依赖.现在,请记住,这发生在非叶子函数中,ebx经常被(被调用者)推入堆栈,因此我不相信这种依赖总是完全免费的.此外,它也用于test reg,reg在完全相同的方式(test/ cmp=> jg).最重要的是,"经典"x86上的寄存器是一种稀缺资源,如果你开始泄漏寄存器,你会浪费很多时间没有充分的理由; 为什么要浪费一个通过所有的功能只是为了保持零?(仍然,考虑一下,我不记得在使用这种"零寄存器"模式的函数中看到很多寄存器溢出).
那么:我错过了什么?它是一个编译器blooper还是一些令人难以置信的智能优化,在2010年特别有趣?
这是一段摘录:
; standard prologue: ebp/esp, SEH, overflow protection, ... then:
xor ebx, ebx
mov [ebp+4], ebx ; zero out some locals
mov [ebp], ebx
call function_1
xor ecx, ecx ; ebx _not_ used to zero registers
cmp eax, ebx ; ... …Run Code Online (Sandbox Code Playgroud) x86 ×8
assembly ×7
optimization ×2
att ×1
boolean ×1
c ×1
c++ ×1
eflags ×1
instructions ×1
math ×1
parity ×1
testing ×1
visual-c++ ×1
x86-16 ×1