64位架构 - 从函数返回时截断的字符指针

时间:2011-01-20 15:55:46

标签: c++ c windows 64-bit

环境:

Windows x64位,5GB RAM。我的二进制文件是64位版本,使用版本编译器构建 - “Microsoft(R)C / C ++优化编译器版本14.00.50727.762 for x64”

环境设置:

Microsoft建议设置以下注册表项以测试64位应用程序,并在我的框中设置相同。如果我没有设置以下注册表,则不会发生此问题,因为程序位于低地址。讨论中提到了相同的注册表项 - As a programmer, what do I need to worry about when moving to 64-bit windows?

要强制分配在较低地址之前从较高地址分配以进行测试,请在调用VirtualAlloc时指定MEM_TOP_DOWN或将以下注册表值设置为0x100000:

HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Memory Management \ AllocationPreference

示例代码:

char *alloc_str()
{
    char *temp;
    temp = (char *) malloc(60);
    /* copy some data to temp */
    return temp;
}

main()
{
    char *str;
    str = (char *)alloc_str();
}

分析:

malloc返回存储在0x000007fffe999b40中的地址temp,但当指针返回main()时,str只获得后半部分0xfffffffffe999b40 1}}我无法访问该位置的数据。

4 个答案:

答案 0 :(得分:6)

关于风格的两点,这有助于诊断这类问题。在使用malloc时,我认为它是作为C程序编译的。在这种情况下,不要在没有必要时进行类型转换。过多的类型转换可能会抑制警告,告诉您没有正确声明您的功能。如果没有原型并且函数定义在另一个模块中,则调用str = (char *)alloc_str();将禁止在没有声明的情况下使用该函数的警告,并且将使用C的默认声明,即所有参数和返回值将是被视为int。 与malloc相同,如果您忘记了正确的包含,您的类型转换将禁止警告,编译器将假定该函数返回int。这可能已经是截断的原因。 另一点,在C中,空参数列表声明为(void)而不是(),其具有另一含义(未指定的参数)。 这些是C和C ++之间不同的两点。

答案 1 :(得分:3)

您引用的注册表设置选择自上而下的内存分配。您声明此设置将“将程序置于高地址空间”。它不会那样做。这样做是迫使Windows内存管理器从地址空间的顶部分配内存。

除了在64位Windows下运行之外,我还没有看到PAE在哪里发挥作用。这将是在32位平台上使用的东西。

我猜你正在编译一个32位应用程序,所以你的指针不可避免地是32位宽。但由于缺乏信息,这只是猜测。

简而言之,你的问题是无法回答的,因为你没有告诉我们你在做什么。

答案 2 :(得分:2)

大卫,谢谢你的时间和建议。示例程序无法正常工作,因为我没有将stdlib.h包含在我的C文件中,因此malloc返回的指针是32位。我遇到的问题是生产代码与示例代码略有不同。

tristopia,你的解释绝对正确。我遇到了同样的问题。

在我的生产C文件中,我遇到了如下问题

<强>交流转换器

call_test1()
{
 char* temp;
 temp = (char *)test1();
}

<强> b.c

include stdlib.h
char* test1()
{
 char *str;
 test = (char *)malloc(60);
 /* copy some data to test*/
 return str;
}

str返回test1()时,指针包含64位地址(我使用“r rx”分析了rx注册表(存储函数的返回值)在windbg中)但是当它被分配给temp,它被截断为32位地址。)

问题是由于

  1. 不在a.c文件中包含test1()的签名
  2. 将返回值进行类型转换为char *
  3. 修改后的来源

    <强>交流转换器

    char * test1();
    call_test1()
    {
     char* temp;
     temp = test1();
    }
    

    <强> b.c

    include stdlib.h
    char* test1()
    {
     char *str;
     test = (char *)malloc(60);
     /* copy some data to test*/
     return str;
    }
    

    我通过反复试验获得了解决方案,但是tristopia解释了原因。

    64位注释

    1. 使用%p而不是%lx以64位环境打印指针的地址。
    2. 包含函数签名并尝试避免使用类型转换指针
    3. 在Windows上, 如果将C / C ++代码重新编译为64位EXE或DLL,则必须使用AllocationPreference注册表值进行测试。
    4. 要强制分配在较低地址之前从较高地址分配以进行测试,请在调用MEM_TOP_DOWN时指定VirtualAlloc或将以下注册表值设置为0x100000

      HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management\AllocationPreference
      

答案 3 :(得分:1)

我不得不问你是否正在使用正确的编译器设置并链接到正确的C运行时库。