我见过很多人相信以下内容
VBA将所有整数值转换为Long类型
事实上,即使是MSDN文章也说
"但是,在最近的版本中,VBA将所有整数值转换为Long类型,即使它们被声明为Integer类型."

这怎么可能?考虑这个简单的例子.
Sub Sample()
Dim I As Integer
I = 123456789
End Sub
Run Code Online (Sandbox Code Playgroud)
如果VBA将所有Integer值转换为类型,Long 即使它们被声明为Integer类型,那么上面的代码永远不会给你Overflow错误!
我在这里错过了什么?或者,我是否应该认为该陈述是错误的并且在开头时注意到该链接所说的内容
在汇编编程中,想要从寄存器的低位计算某些东西是相当普遍的,这些位不能保证将其他位置零.在像C这样的高级语言中,你只需将输入转换为小尺寸,让编译器决定是否需要分别将每个输入的高位归零,或者是否可以在输出之后切断结果的高位.事实.
这是为x86-64的(又名AMD64),出于各种原因尤其常见1,其中的一些是存在于其它的ISA.
我将使用64位x86作为示例,但目的是询问/讨论2的补码和无符号二进制算法,因为所有现代CPU都使用它.(注意,C和C++不保证两个补码4,并且有符号溢出是未定义的行为.)
作为示例,考虑一个可以编译为LEA指令2的简单函数.(在X86-64 SysV的(Linux)的ABI 3,前两个函数参数是rdi和rsi,与在返回rax. int是一个32位的类型.)
; int intfunc(int a, int b) { return a + b*4 + 3; }
intfunc:
lea eax, [edi + esi*4 + 3] ; the obvious choice, but gcc can do better
ret
Run Code Online (Sandbox Code Playgroud)
gcc知道即使是负有符号整数,加法也只是从右到左,所以输入的高位不会影响进入的内容eax.因此,它保存了一个指令字节并使用 lea eax, [rdi + rsi*4 + 3]
为什么它有效?
1为什么x86-64频繁出现这种情况:x86-64有可变长度指令,其中额外的前缀字节改变了操作数大小(从32到64或16),因此在指令中通常可以保存一个字节.以相同的速度执行.当写入低8b或16b的寄存器(或稍后读取完整寄存器(Intel pre-IvB)时的失速)时,它也具有错误依赖性(AMD/P4/Silvermont):由于历史原因, …
在另一个问题中,有人想知道为什么他们得到一个"浮点错误",实际上他们的C++程序中有一个整数除零.围绕这一点进行了讨论,其中一些断言浮点异常实际上从未因浮点除以零而增加,而只是在整数除以零时出现.
这听起来很奇怪,因为我知道:
所有Windows平台上x86和x64上的MSVC编译代码报告int除以零为"0xc0000094:整数除以零",浮点除以零为0xC000008E"浮点除以零"(启用时)
IA-32和AMD64 ISA指定#DE(整数除法异常)作为中断0.浮点异常触发中断16(x87浮点)或中断19(SIMD浮点).
其他硬件具有类似的不同中断(例如, PPC在float-div-by上引发0x7000并且根本不捕获int/0).
我们的应用程序使用_controlfp_s内部(最终stmxcsr操作)取消屏蔽零除零的浮点异常,然后捕获它们以进行调试.所以我在实践中肯定会看到IEEE754被零除的异常.
因此,我得出结论,有些平台将异常作为浮点异常报告,例如x64 Linux(无论ALU管道如何,都会针对所有算术错误提升SIGFPE).
其他操作系统(如果您是操作系统,还是C/C++运行时)报告整数除零作为浮点异常?
我的任务是表达一些看似奇怪的C代码行为(在x86上运行).我可以很容易地完成其他所有事情,但这个让我很困惑.
代码段1输出
-2147483648Run Code Online (Sandbox Code Playgroud)int a = 0x80000000; int b = a / -1; printf("%d\n", b);
代码片段2没有输出任何内容,并给出了一个
Floating point exceptionRun Code Online (Sandbox Code Playgroud)int a = 0x80000000; int b = -1; int c = a / b; printf("%d\n", c);
我很清楚Code Snippet 1(1 + ~INT_MIN == INT_MIN)的结果的原因,但是我不太明白整数除以-1如何生成FPE,也不能在我的Android手机(AArch64,GCC 7.2.0)上重现它.代码2只输出与代码1相同,没有任何例外.它是x86处理器的隐藏bug功能吗?
该任务没有告诉任何其他内容(包括CPU架构),但由于整个课程基于桌面Linux发行版,您可以放心地认为它是一个现代的x86.
编辑:我联系了我的朋友,他在Ubuntu 16.04(Intel Kaby Lake,GCC 6.3.0)上测试了代码.结果与所指定的任何内容一致(代码1输出所述内容,代码2与FPE崩溃).
我正在通过《计算机系统从程序员的角度》(第3版)一书中介绍x86-64(以及一般而言的汇编)。根据网络上的其他来源,作者声明idivq只采用一个操作数-就像这个声称的那样。但是随后,作者(在某些章节之后)给出了带有说明的示例idivq $9, %rcx。
两个操作数?我首先以为这是一个错误,但从那本书开始就经常发生。
同样,应该从寄存器%rdx(高阶64位)和%rax(低阶64位)中的数量中获得红利-因此,如果在体系结构中定义了该数量,则似乎不可能指定第二个操作数股利。
这是一个练习的示例(懒得将其全部写下来-因此,图片是必经之路)。它声称idivq $9, %rcx编译短C函数时会发出GCC 。
在Delphi的math.pas单元中有一个DivMod程序,我希望将其转换为内联并优化它,除数总是为10.但我不知道五角大楼ASM的细节.波纹管程序的转换是什么?
procedure DivMod(Dividend: Integer; Divisor: Word;
var Result, Remainder: Word);
asm
PUSH EBX
MOV EBX,EDX
MOV EDX,EAX
SHR EDX,16
DIV BX
MOV EBX,Remainder
MOV [ECX],AX
MOV [EBX],DX
POP EBX
end;
Run Code Online (Sandbox Code Playgroud) 我正在努力idiv工作正常而且我已经读过你把你想要划分的东西比如25然后在ebx你把你想要划分的东西比如5然后你做
idiv ebx
Run Code Online (Sandbox Code Playgroud)
然后将EAX= 5然后EDX= 0.
但是它在我的程序中没有这样做我输入的是100000000
输出:
Kilobytes:1亿
兆字节:1869375819
想知道我在这里做错了什么?
%include "asm_io.inc"
;
; initialized data is put in the .data segment
;
segment .data
prompt db "Please enter the number of bytes:", 0
param db "1 = Calculate it in kilobytes", 0Ah, "2 = Calculate it in megabytes", 10, 0
output db "Kilobytes: %d", 0Ah, "MegaBytes: %d", 10, 0
;
;
segment .bss
;
input resd 1
input2 resd …Run Code Online (Sandbox Code Playgroud) 我正在自学一些使用 x86-64 Mac OS 的汇编编程。我试图弄清楚为什么在将正整数除以负整数时会溢出。例如,5/-2必须返回-2。但是,就我而言,它2147483371在我执行时返回 a-554/2而不是-277...这是我的程序集文件中的内容:
; compiling using: nasm -f macho64 -o divide.o divide.s
[bits 64]
global _divide
section .text
; int divide(int dividend, int divisor)
_divide:
xor rdx, rdx ; making this to 0
push rbp ; base stack pointer
mov rax, rdi ; dividend
mov rcx, rsi ; divisor
idiv rcx ; integer division
add rsp, 8
ret
Run Code Online (Sandbox Code Playgroud)
在我的main.c文件中,我有这个:
#include <stdio.h>
extern int divide(int dividend, …Run Code Online (Sandbox Code Playgroud) 有人可以帮助我理解unsigned long long在性能方面使用asm块进行乘法的好处.它与竞争性编程优化有关.我想它会使乘法更快,但我实际上无法理解代码.
const int md = 998244353;
inline int mul(int a, int b)
{
#if !defined(_WIN32) || defined(_WIN64)
return (int) ((long long) a * b % md);
#endif
unsigned long long x = (long long) a * b;
unsigned xh = (unsigned) (x >> 32), xl = (unsigned) x, d, m;
asm(
"divl %4; \n\t"
: "=a" (d), "=d" (m)
: "d" (xh), "a" (xl), "r" (md)
);
return m;
}
Run Code Online (Sandbox Code Playgroud) 据我了解,idiv %ebx将除以edx:eax32 位(按顺序连接成 64 位值)ebx。
但是,当我尝试将0x00000000:0xfffffffb(0 和 -5)除以0xffffffff(-1)时,出现浮点异常。
有人可以解释为什么吗?我很困惑为什么会发生这种情况,因为我毕竟没有除以 0。
请注意,我知道我需要签署扩展edx:eax才能实现我想要的,即计算-5/-1。然而,即使没有符号扩展,下面的内容也不会导致 FPE。
在使用 .x86 程序集除以 0 时,出现 SIGFPE 异常idiv。我如何从汇编中禁用它?我需要系统调用还是可以直接在 x86 中完成?
再生产:
测试.asm
default rel
global WinMain
section .data
section .text
WinMain:
mov rcx, 0
mov rdx, 0
idiv rcx
Run Code Online (Sandbox Code Playgroud)
命令:
nasm -f win64 test.asm
gcc test.obj
gdb a
运行
我注意到EDX包含一些随机默认值,如00401000,然后我使用这样的DIV指令:
mov eax,10
mov ebx,5
div ebx
Run Code Online (Sandbox Code Playgroud)
它会导致INTEGER OVERFLOW ERROR.但是,如果我设置edx为0并执行相同的操作.我相信使用div会导致商重写eax和其余覆盖edx.
获得此INTEGER OVERFLOW ERROR确实让我感到困惑.
我有这两个代码片段:
mov ax, word [wNum2]
cwd
div word [wNum3]
mov [wAns16], dx
Run Code Online (Sandbox Code Playgroud)
movzx eax, word [wNum2]
;cwd
div word [wNum3]
mov [wAns16], edx
Run Code Online (Sandbox Code Playgroud)
第一个产生正确的答案,第二个会给我一个大约一百左右的答案,除非我取消注释 cwd。
我的问题是,我认为 movzx 会为我清零所有内容,这将使 cwd 不再需要。我完全误解了它们的工作原理吗?有人可以引导我完成这些代码片段吗?