c++ - 来自数组 0 初始化的奇怪程序集

标签 c++ c compiler-construction assembly

受问题 Difference in initalizing and zeroing an array in c/c++ ? 启发,我决定实际检查 Windows Mobile Professional(ARM 处理器,来自 Microsoft Optimizing Compiler)的优化版本构建的程序集。我的发现有点令人惊讶,我想知道是否有人可以解释我的问题。

检查这两个示例:

byte a[10] = { 0 };

byte b[10];
memset(b, 0, sizeof(b));

它们用在同一个函数中,所以栈是这样的:

[ ] // padding byte to reach DWORD boundary
[ ] // padding byte to reach DWORD boundary
[ ] // b[9] (last element of b)
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ] // b[0] = sp + 12 (stack pointer + 12 bytes)
[ ] // padding byte to reach DWORD boundary
[ ] // padding byte to reach DWORD boundary
[ ] // a[9] (last element of a)
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ] // a[0] = sp (stack pointer, at bottom)

带有我的评论的生成程序集:

; byte a[10] = { 0 };

01: mov   r3, #0        // r3 = 0
02: mov   r2, #9        // 3rd arg to memset: 9 bytes, note that sizeof(a) = 10
03: mov   r1, #0        // 2nd arg to memset: 0-initializer
04: add   r0, sp, #1    // 1st arg to memset: &a[1] = a + 1, since only 9 bytes will be set
05: strb  r3, [sp]      // a[0] = r3 = 0, sets the first element of a
06: bl    memset        // continue in memset

; byte b[10];
; memset(b, 0, sizeof(b));

07: mov   r2, #0xA      // 3rd arg to memset: 10 bytes, sizeof(b)
08: mov   r1, #0        // 2nd arg to memset: 0-initializer
09: add   r0, sp, #0xC  // 1st arg to memset: sp + 12 bytes (the 10 elements
                        // of a + 2 padding bytes for alignment) = &b[0]
10: bl    memset        // continue in memset

现在,有两件事让我感到困惑:

  1. 第 2 行和第 5 行有什么意义?为什么不直接给 memset &a[0] 和 10 个字节?
  2. 为什么没有初始化 0 的填充字节?这仅适用于结构中的填充吗?

编辑:我很好奇不测试结构案例:

struct Padded
{
    DWORD x;
    byte y;
};

0 初始化它的汇编器:

; Padded p1 = { 0 };

01: mov   r3, #0
02: str   r3, [sp]
03: mov   r3, #0
04: str   r3, [sp, #4]

; Padded p2;
; memset(&p2, 0, sizeof(p2));

05: mov   r3, #0
06: str   r3, [sp]
07: andcs r4, r0, #0xFF
08: str   r3, [sp, #4]

在这里,我们在第 04 行看到确实发生了填充,因为使用了 str(与 strb 相对)。对吧?

最佳答案

第 2 行和第 5 行的原因是因为您在数组初始值设定项中指定了 0。编译器将初始化所有常量,然后使用 memset 填充其余的常量。如果你在初始化器中放两个零,你会看到它是 strw(字而不是字节)然后 memset 8 个字节。

至于padding,它只是用来对齐内存访问——一般情况下不应该使用数据,所以memsetting很浪费。

编辑:为了记录,我对上面的 strw 假设可能是错误的。我 99% 的 ARM 经验是在 iPhone 上反转 GCC/LLVM 生成的代码,所以我的假设可能不会延续到 MSVC。

关于c++ - 来自数组 0 初始化的奇怪程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/531477/

相关文章:

optimization - 是否有用于在简单处理器上生成自修改代码的高级语言的现代编译器?

c++ - 如何在 C++ 中提高 int 或 long 的幂

Visual Studio 和 Eclipse 中的 C++ 图形库

python bytearray 到 C++ 对象

c++ - 如何从网络摄像头压缩 mjpeg native 格式帧

java - 编译器似乎混淆了重载方法的两个版本。为什么?

.net - 为什么构造的委托(delegate)类的调用方法是虚拟的?

c++将数据源函数作为参数传递

c - 什么是 (void (**) ()) 以及如何对它进行类型定义?

c - 为什么 C 中需要 volatile?