我有这个示例代码:
struct
{
char a[2];
char b[2];
} buff;
char buffer1[5] = "ABCD";
要将buffer1
复制到结构成员,我这样做:
char c[3],d[3];
memcpy(&buff,buffer1,4);
sprintf(c,"%2.2s",buff.a);
sprintf(d,"%2.2s",buff.b);
printf("c=%s,d=%s",c,d);
当我打印变量c和d时,我正确地将c和d变量中的值变为:c="AB"
和c="CD"
。
我的问题是,即使我正确地获得了输出,memcpy
会影响与空字符终止相关的任何内容,还是会产生其他与意外内存相关的后果?
答案 0 :(得分:7)
这里有两个问题:
1)如评论中所述,可能忘记为结尾'\0'
(即ASCII中的NUL
)终结符字符添加空格。 %s
函数的printf
格式说明符期望字符串的格式有效。然而,没有什么可以阻止你打印成字符序列,如下所示:
#include <stdio.h>
#include <string.h>
struct {
char a[2];
char b[2];
} buff;
char buffer1[5] = "ABCD";
int main(void)
{
memcpy(&buff, buffer1, 4);
printf("First member: %c%c\n", buff.a[0], buff.a[1]);
printf("Second member: %c%c\n", buff.b[0], buff.b[1]);
return 0;
}
2)更严重的问题是编译器可能在结构成员之间(以及在最后一个成员之后)包含任意填充,因此memcpy
可能无法按预期工作。而不是像那样复制(因为它可能将数组中的字节放入未使用的“整体”)。我会建议每个成员的个人副本,或者使用offsetof()
宏。
来自N1570 6.7.2.1/15
结构和联合说明符:
结构对象中可能有未命名的填充,但不在其中 开始。
和6.7.2.1/17
:
结构或联合的末尾可能有未命名的填充。
因此,您应该将memcpy
分成两个调用,例如:
memcpy(&buff.a, buffer1, 2); /* or replace 2 with sizeof buff.a */
memcpy(&buff.b, buffer1+2, 2);
答案 1 :(得分:1)
buffer1
以null结尾。但是,buff
的数据成员不是,因为您不会在它们上附加空终结符。而且,你没有空终止器的空间!
所以,没有它不会影响它,因为它不存在。当您尝试使用stdio.h
的函数时,您会得到意外的结果,这些函数期望一个空终止的字符串。
此外,您可能希望检查我的示例here,关于在结构中循环,它有点相关。我建议您一次复制到一个数据成员,一次不。
答案 2 :(得分:1)
这可能无法按预期工作。结构中的字段之间可能存在填充字节。它们插入字段之间,以使下一个字段以某个地址偏移量开始。这主要是CPU的字大小或总线大小,或者是高速缓存对齐的倍数。
即使对于char []
也是如此,因为这样可以使用单词传输有效地移动/复制这些数组。
对于其他类型,填充很可能,另外你必须关心endianess。
还要记住memcpy
&amp;朋友们完全按照他们的名字暗示:他们在一块记忆中运作。他们不关心字符串,他们对“字符串”没有任何想法。插入任何NUL字节会使它们无用,所以它们不会。
请注意,此方法类似于强制转换不兼容的指针类型。你很安全的地方很少,但大多数时候这是通往地狱的道路(又名未定义的行为)。
答案 3 :(得分:-1)
#include<stdio.h>
#include<string.h>
struct
{
char a[2];
char b[2];
}buff;
int main ( void )
{
char buffer1[4] = "ABCD";
memcpy ( &buff , buffer1 , 4 );
printf ( "\n%s\n ", buff.a );
printf ( "\n%s\n ", buff.b );
return ( 0 );
}
o/p-->
rabi@rabi-VirtualBox:~/rabi/c$ gcc 16.c
rabi@rabi-VirtualBox:~/rabi/c$ ./a.out
ABCD
CD
rabi@rabi-VirtualBox:~/rabi/c$
#include<stdio.h>
#include<string.h>
struct
{
char a[3];
char b[3];
}buff;
int main ( void )
{
char buffer1[4] = "ABCD";
memcpy ( &buff.a , &buffer1[0], 2 );
buff.a[2]='\0';
memcpy ( &buff.b , &buffer1[2], 2 );
buff.b[2]='\0';
printf ( "\n%s\n ", buff.a );
printf ( "\n%s\n ", buff.b );
return ( 0 );
}
o/p--->
rabi@rabi-VirtualBox:~/rabi/c$ gcc 15.c
rabi@rabi-VirtualBox:~/rabi/c$ ./a.out
AB
CD
rabi@rabi-VirtualBox:~/rabi/c$