返回介绍

18.2 让我们用 malloc() 为结构体分配空间

发布于 2025-02-22 14:00:47 字数 2630 浏览 0 评论 0 收藏 0

但是,有时候把结构体放在堆中而不是栈上却更简单:

#!cpp
#include <windows.h>
#include <stdio.h>
void main()
{
    SYSTEMTIME *t;
    t=(SYSTEMTIME *)malloc (sizeof (SYSTEMTIME));
    GetSystemTime (t);
    printf ("%04d-%02d-%02d %02d:%02d:%02d
",
    t->wYear, t->wMonth, t->wDay,
    t->wHour, t->wMinute, t->wSecond);
    free (t);
    return;
};

让我们用优化/Ox 编译一下它,看看我们得到什么东西

清单 18.4: 优化的 MSVC

#!bash
_main PROC
    push esi
    push 16 ; 00000010H
    call _malloc
    add esp, 4
    mov esi, eax
    push esi
    call DWORD PTR __imp__GetSystemTime@4
    movzx eax, WORD PTR [esi+12] ; wSecond
    movzx ecx, WORD PTR [esi+10] ; wMinute
    movzx edx, WORD PTR [esi+8] ; wHour
    push eax
    movzx eax, WORD PTR [esi+6] ; wDay
    push ecx
    movzx ecx, WORD PTR [esi+2] ; wMonth
    push edx
    movzx edx, WORD PTR [esi] ; wYear
    push eax
    push ecx
    push edx
    push OFFSET $SG78833
    call _printf
    push esi
    call _free
    add esp, 32 ; 00000020H
    xor eax, eax
    pop esi
    ret 0
_main ENDP

所以,sizeof(SYSTEMTIME) = 16, 这正是 malloc 所分配的字节数。它返回了刚刚分配的地址空间,这个指针存在 EAX 寄存器里。然后,这个指针会被移动到 ESI 结存器中, GetSystemTime() 会用它来存储返回值,这也就是为什么这里分配完之后并没有把 EAX 放到某个地方保存起来,而是直接使用它的原因。

新指令:MOVZX(Move with Zero eXtent, 0 扩展移动)。它可以说是和 MOVSX 基本一样(13.1.1 节),但是,它把其他位都设置为 0。这是因为 printf() 需要一个 32 位的整数,但是我们的结构体里面是 WORD,这只有 16 位厂。这也就是为什么从 WORD 复制到 INT 时第 16~31 位必须清零的原因了。因为,如果不清除的话,剩余位可能有之前操作留下来的干扰数据。

在下面这个例子里面,我可以用 WORD 数组来重现这个结构:

#!cpp
#include <windows.h>
#include <stdio.h>
void main()
{
    WORD *t;
    t=(WORD *)malloc (16);
    GetSystemTime (t);
    printf ("%04d-%02d-%02d %02d:%02d:%02d
",
    t[0] /* wYear */, t[1] /* wMonth */, t[3] /* wDay */,
    t[4] /* wHour */, t[5] /* wMinute */, t[6] /* wSecond */);
    free (t);
    return;
};

我们得到:

#!bash
$SG78594 DB ’%04d-%02d-%02d %02d:%02d:%02d’, 0aH, 00H
_main PROC
    push esi
    push 16 ; 00000010H
    call _malloc
    add esp, 4
    mov esi, eax
    push esi
    call DWORD PTR __imp__GetSystemTime@4
    movzx eax, WORD PTR [esi+12]
    movzx ecx, WORD PTR [esi+10]
    movzx edx, WORD PTR [esi+8]
    push eax
    movzx eax, WORD PTR [esi+6]
    push ecx
    movzx ecx, WORD PTR [esi+2]
    push edx
    movzx edx, WORD PTR [esi]
    push eax
    push ecx
    push edx
    push OFFSET $SG78594
    call _printf
    push esi
    call _free
    add esp, 32 ; 00000020H
    xor eax, eax
    pop esi
    ret 0
_main ENDP

同样,我们可以看到编译结果和之前一样。个人重申一次,你不应该在写代码的时候用这么晦涩的方法来表达它。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文