交换指针而不是memcpy

时间:2011-03-27 20:34:05

标签: c optimization pointers swap memcpy

编辑:对于我的代码段中的错误,我很抱歉,现在我看到两个输出都相同。以下是经过编辑的版本。

假设我有一个结构:

typedef struct
{
    char m[5];
    char f[6];
} COUPLE;

一个只包含我读入数组的短语RomeoJuliet的文件:

char *data = malloc(11);
FILE *f = fopen("myfile", "rb");
fread(data, 1, 11, f);
fclose(f);

当我需要从字节数组填充我的结构时,我总是使用这段代码:

COUPLE titanic;
memcpy(&titanic, data, sizeof(data));
printf("%s and %s", titanic.m, titanic.f);

这很好用,但实际上我的字节数组可能非常大,所以下面是我尝试优化代码。

COUPLE *titanic = (COUPLE *)data;
printf("%s and %s", titanic->m, titanic->f);

所以,我的问题是:

  1. (已废弃)为什么我会得到不同的输出?
  2. (已废弃)如何通过从数组中强制转换来填充结构?
  3. 我应该避免这种优化吗?
  4. 是否有可能存在陷阱?

4 个答案:

答案 0 :(得分:2)

你所说的不是真的。你使用memcpy从字符串填充结构的方法不会也不起作用。首先,当你做

memcpy(&titanic, data, sizeof(data));

您正在从char数组中复制12个字节。同时,结构不保证大12字节(总大小只有11),因此一般情况下会导致内存溢出。

其次,titanic.m中的char数组不会被终止。对于titanic.f也是如此,这就是为什么您的printf绝对没有更改输出"Romeo and Juliet",因为您错误地声称。

你声称你的第一个例子“工作正常”(为什么?),而实际上第一个例子根本不起作用,即使它“有效”,它也会遇到与你的第二个例子非常相似的问题(虽然一般情况下,确切的问题是不可预测的。)

您尝试使用的方法不可行。您无法从一个原始字符串生成一个正确形成的结构,其中包含两个字符串。无法完成的一个明显原因是,对于两个字符串,您需要两个零终止符,而原始字符串只有一个。

答案 1 :(得分:1)

  1. 因为成员从不同的位置开始。 Printf()打印一个空(\ 0)终止的句子。
  2. 你可以这样做。但是你需要注意类型以及如何使用它们。
  3. 如果你知道自己在做什么,那就好了。
  4. 如果你不知道自己在做什么,很多陷阱......没有类型安全。

答案 2 :(得分:1)

当我对你的问题发表评论时,我没有时间详细说明,所以这是尝试回答。代码已经改变了,我不确定我是否会像现在这样将代码添加到代码中。

尽管如此,让我添加该评论的根本原因仍然存在: 除非您测量 并发现相关代码确实对性能产生了重大负面影响, 不要尝试优化 。相反,努力使您的代码 尽可能可读

我严重怀疑在将数据从磁盘复制到内存后,复制内存中的数据会对性能产生重大影响。但是,由于您提供的代码无论如何都会假设结构在内存中的布局,直接读取结构并不会真正使代码的可读性降低(或者更不容易受到对该布局的更改):

COUPLE titanic;
FILE *f = fopen("myfile", "rb");
fread(&titanic, sizeof(titanic), 1, f);

或者,如果你确实有一个数组,请直接读入数组:

COUPLE titanic[SIZE];
FILE *f = fopen("myfile", "rb");
fread(&titanic, sizeof(titanic), SIZE, f);

取决于SIZE,后者确实可能在性能方面产生巨大的差异。对于较大的块,访问磁盘以获得更大的块通常更快。 (尽管磁盘缓存可能会减轻这种情况。)

答案 3 :(得分:1)

我认为唯一不涉及memcpy的解决方案是直接从文件到结构读取的解决方案。这可能是这样的

typedef struct
{
    char m[6];
    char f[7];
} COUPLE;

COUPLE titanic;

FILE *f = fopen("myfile", "rb");
fread(titanic.m, 1, 5, f);
titanic.m[5] = '\0';
fread(titanic.f, 1, 6, f);
titanic.f[6] = '\0';
fclose(f);

printf("%s and %s", titanic.m, titanic.f);

当然这个例子可能并不是最优的,因为我认为一次fread和几次memcpy的调用会比2次fread更快。这样或那样的解决方案都是非常不现实的,因为问题是不现实的 - 谁需要存储5和6字符长度名称的结构。