【问题标题】:C memcpy behaves differently on Linux and WindowsC memcpy 在 Linux 和 Windows 上的行为不同
【发布时间】:2013-12-24 13:32:35
【问题描述】:

好的,首先描述一下我的问题。我有一个示例程序,只有一个文件。唯一包含的头文件是标准库的一部分。为了训练和测试,我编写了自己的 malloc 包装器,它会自动将 0 写入整个存储块。在我的上网本(Debian + Gnome 桌面,像这样的原始 gcc 调用:gcc memstest.c -o memstest)它运行没有问题。即使由于基准测试,我删除了对存储的每个部分的整个迭代检查,但对任何其他数据然后 0 的检查都是成功的。在 Windows 上尝试使用 Code::Blocks 作为 IDE 并配置 GNU gcc 编译器时,它告诉我在分配的存储中存在数据(大多数时候值为 -60)。正如所见,我主要只使用无符号值,因此在将其写入数据块时,该值不可能是我的失败。我猜是memcpy 函数,因为它是唯一触及这个数据块的例程。如果我记错了,我会更改主题标题。

这是我的示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iso646.h>
#include <time.h>

void *Smalloc_dyn( unsigned int n_bytes );

int main( void )
{
    time_t start_t, end_t;
    double difference;
    unsigned int index = 0;
    start_t = time( NULL );
    for( index = 0; index < 10000000; index++ )
    {
        char *test = Smalloc_dyn( 65536 );
        if( *test != 0 )
        {
            printf( "Found data without 0 overwriting...\n" );
            return 0;
        }
        free( test );
    }
    end_t = time( NULL );
    difference = difftime( end_t, start_t );
    printf( "Smalloc_dyn took %.1fs\n", difference );
    start_t = time( NULL );
    for( index = 0; index < 10000000; index++ )
    {
        char *test = calloc( ( 65535 / sizeof( (long) 0 ) ), ( 65536 / ( 65535 / sizeof( (long) 0 ) ) ) );
        if( *test != 0 )
        {
            printf( "Found data without 0 overwrting...(2)\n" );
            return 0;
        }
        free( test );
    }
    end_t = time( NULL );
    difference = difftime( end_t, start_t );
    printf( "calloc took %.1fs\n", difference );
    return 0;
}

void *Smalloc_dyn( unsigned int n_bytes )
{
    /*
    This fusion of malloc and a modified memset
    is way faster than calling malloc() and
    after that memset( *dst, 0, len(dst) ).
    We are defining 0 as a long and will
    therefore copy ( for example ) 8 Bytes
    instead of a per-byte copying.
    With a memory need of 1024, we only
    have 128 steps instead of 1024.
    */
    if( 0 == n_bytes )
    {
        return NULL;
    }
    long unsigned int chr = 0;
    unsigned int steps = sizeof( chr ) / n_bytes;
    unsigned int asteps = n_bytes % sizeof( chr );
    unsigned int index = 0;
    char *mem_ptr = malloc( n_bytes );
    if( NULL == mem_ptr )
    {
        return mem_ptr;
    }
    char *write_ptr = mem_ptr;
    for( index = 0; index < steps; index++ )
    {
        memcpy( write_ptr, &chr, sizeof( chr ) );
        write_ptr = write_ptr + sizeof( chr );
    }
    for( index = 0; index < asteps; index++ )
    {
        memcpy( write_ptr, &chr, 1 );
        write_ptr = write_ptr + 1;
    }
    return mem_ptr;
}

编辑:更正的代码

【问题讨论】:

  • 所以你意识到 sizeof(chr)/n_bytes 将是零,对吧?整数 4/65536 为 0。asteps 也为 0,因为 65536 % 4 为 0。所以你根本不会调用 memset。也许这就是它“更快”的原因:)
  • 这又是“由于树木太多而看不到森林”的例子之一。我正在寻找某种价值错误。好的,又是一个很好的教训,重新阅读自己的代码超过 2 次 :)

标签: c linux windows memory gcc


【解决方案1】:

为什么steps 的值被评估为

unsigned int steps = sizeof( chr ) / n_bytes;

而不是像

unsigned int steps = n_bytes / sizeof( chr );

?

这似乎是问题的潜在根源,因为大部分分配的块将由于此错误而未初始化。在“大多数”情况下,steps 最终会为零(就像在您的测试用例中,nbytes65536)。未初始化的数据很容易在平台之间“表现”不同。

【讨论】:

  • 在这个测试程序中,steps和asteps都是0,所以memset一次都没有被调用。
  • 哦,我的...好的,谢谢大家。所以只是我的一种。我会在一段时间后删除这个话题以保持这个干净。非常感谢。
  • @fairiestoy:删除问题会带走 AndreyT 因赞成和接受而获得的积分。让问题保持原样;如果其他人认为它没有用,他们可能会投票关闭和/或删除它。
猜你喜欢
  • 2021-04-26
  • 2019-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-11
  • 1970-01-01
相关资源
最近更新 更多