交换指针而不是 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);
所以,我的问题是:(
- 已过时)为什么我会得到不同的输出?
- (已过时)如何仅通过从数组进行转换来填充结构?
- 我应该避免这种优化吗?
- 其中是否有可能存在陷阱?
EDIT: I'm sorry for my mistakes in my code snippets, now I see both outputs were same. Below is an edited version.
Let's say I have a structure:
typedef struct
{
char m[5];
char f[6];
} COUPLE;
And a file containing just phrase RomeoJuliet
that I read into an array:
char *data = malloc(11);
FILE *f = fopen("myfile", "rb");
fread(data, 1, 11, f);
fclose(f);
I always use this code when I need to fill my structure from a byte array:
COUPLE titanic;
memcpy(&titanic, data, sizeof(data));
printf("%s and %s", titanic.m, titanic.f);
This works fine, but really my byte array can be very big, so below is my attempt to optimize my code.
COUPLE *titanic = (COUPLE *)data;
printf("%s and %s", titanic->m, titanic->f);
So, my questions are:
- (obsolete) Why do I get different outputs?
- (obsolete) How can I fill a structure just by casting from an array?
- Should I avoid this kind of optimization?
- Are there possible pitfalls in it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你所说的不是真的。如果使用memcpy从字符串填充结构,则您的方法不会并且不起作用。首先,当您这样做时,
您将从 char 数组中复制 12 个字节。同时,结构体不保证为12字节大(总大小只有11字节),因此一般情况下会导致内存溢出。
其次,
titanic.m
中的 char 数组不会以零结尾。titanic.f
也是如此,这就是为什么你的printf
输出"Romeo and Juliet"
完全没有变化,因为你错误地宣称。您声称您的第一个示例“工作正常”(为什么?),而实际上第一个示例根本不起作用,即使它“工作”,它也会遇到与第二个示例非常相似的问题(尽管在一般情况下)确切的问题将无法预测)。
您尝试使用的方法不可行。您无法从一个原始字符串生成包含两个字符串的格式正确的结构。无法完成此操作的一个明显原因是,对于两个字符串,您需要两个零终止符,而原始字符串只有一个。
What your are saying is not true. You method if filling a struct from a string my using
memcpy
will not and does not work. Firstly, when you doyou are copying 12 bytes from the char array. Meanwhile, the struct is not guaranteed to be 12 bytes large (the total size is only 11), so it will cause memory overrun in general case.
Secondly, the char array in
titanic.m
will not be zero terminated. The same is true fortitanic.f
, which is why yourprintf
has absolutely no change of outputing"Romeo and Juliet"
, as you falsely claim.You claim that your first example "works fine" (why?), while in reality the first example does not work at all, and even when it "works" it suffers from the very similar problems to your second example (although in general case the exact problems will not be predictable).
The approach you are trying to use is not viable. You can't produce a correctly formed struct with two strings in it from one original string. One obvious reason why it can't be done is that for two strings you need two zero-terminators, while your original string has only one.
当我对你的问题发表评论时,我没有时间详细说明,所以这里尝试回答。此后代码已更改,我不确定是否会像现在一样将该注释添加到代码中。
尽管如此,让我添加该评论的根本原因仍然存在:除非您进行了测量并发现相关代码确实对性能产生了显着的负面影响,不要尝试优化。相反,努力使您的代码尽可能具有可读性。
我严重怀疑将数据从磁盘复制到内存后,将数据复制到内存中会对性能产生重大影响。但是,由于您提供的代码无论如何都对结构在内存中的布局做出了假设,因此直接读入结构并不会真正降低代码的可读性(或不易受到该布局更改的影响):
或者,如果您确实有一个数组,直接读入数组:
根据
SIZE
,后者确实可能在性能上产生潜在的巨大差异。一般来说,访问磁盘的较大块比访问较小的块更快。 (尽管磁盘缓存可能会缓解这种情况。)When made my comment to your question, I didn't have the time to elaborate, so here's an attempt to answer. The code has changed since, and I'm not sure I would add that comment to the code as it is now.
Nevertheless, the underlying reason that made me add that comment still stands: Unless you measured and found that the code in question does indeed have a significant negative impact on performance, don't attempt to optimize. Instead, strive to make your code as readable as possible.
I seriously doubt that copying the data in memory will have a significant performance impact after copying them from the disk into memory. However, since your code as provided makes assumptions about the struct's layout in memory anyway, directly reading into the struct wouldn't really make the code less readable (or less vulnerable to changes to that layout):
Or, if you indeed have an array, read into the array directly:
Depending on
SIZE
, the latter could indeed make a potentially huge difference in performance. Accessing the disk for bigger chunks is, in general, faster that doing it for smaller chunks. (Although disk caching might alleviate that.)我认为唯一不涉及 memcpy 的解决方案是直接从文件读取到结构的解决方案。 当然这个例子可能
不是最佳的,因为我认为一次 fread 调用和几个 memcpy 会比 2 个 fread 更快。无论哪种方式,这两种解决方案都是非常不现实的,因为问题是不现实的 - 谁需要存储 5 和 6 个字符长度名称的结构。
I think that the only solution that doesn't involves memcpy would be solution that directly read from file to structure. This could be something like this
Of course this example probably is not optimal, because I think that one call of fread and few memcpy would be faster than 2 freads. That way or another both solutions are very unrealistic, because the problem is unrealistic - who needs structure that stores 5 and 6 character length name.