简体   繁体   English

memcpy会正确复制一个字符串吗?

[英]Will memcpy copy a string correctly?

I am working on implementing some low-level file writing, where the file format is specific down to each bit. 我正在努力实现一些低级文件写入,其中文件格式特定于每个位。 I need to copy a string from an NSString into null-terminated string with length 16 (which is not assignable, according to Xcode). 我需要将NSString的字符串复制到长度为16的以null结尾的字符串(根据Xcode,这是不可分配的)。 I am a total n00b when it comes to c , and want to be sure I understand this correctly. 当涉及到c时我总是n00b ,并且想确保我理解正确。 This is what I am currently doing: 这就是我目前正在做的事情:

//I have a non-null NSString called _friendly_name.
const char *string = [_friendly_name UTF8String];
//profile.friendly is a utf-8 null-terminated string
memcpy(&profile.friendly_name, &string, 16);

This has not yet been tested, but I want to be sure this will work. 这还没有经过测试,但我想确定这会有效。 Will this provide the behavior I am expecting? 这会提供我期待的行为吗? Or should I be copying the string a different way (such as strcpy )? 或者我应该以不同的方式复制字符串(例如strcpy )?

You can use memcpy() or strcpy() , but you'll have to do the bounds checking yourself and there are other errors in your code. 您可以使用memcpy()strcpy() ,但是您必须自己进行边界检查,并且代码中还有其他错误。

So, I take it you want to copy an NSString into a char[16] array. 所以,我认为你想将NSString复制到char[16]数组中。 You can use an NSString builtin method to do this, and you don't have to use memcpy() yourself: 您可以使用NSString内置方法来执行此操作,并且您不必自己使用memcpy()

NSString *src;
char dest[16];
NSUinteger destlen;
[src getBytes:dest
    maxLength:sizeof(dest) - 1
    usedLength:&destlen
    encoding:NSUTF8StringEncoding
    options:0
    range:NSMakeRange(0, [src length])
    remainingRange:NULL];
dest[destlen] = '\0';

If you want to use memcpy() , then you'll have to do it this way: 如果你想使用memcpy() ,那么你必须这样做:

NSString *src;
char dest[16], *srcUtf8;
size_t len;

srcUtf8 = [src UTF8String];
len = strlen(srcUtf8);
if (len >= sizeof(dest))
    len = sizeof(dest) - 1;
memcpy(dest, srcUtf8, len);
dest[len] = '\0';

Errors in your code 代码中的错误

This code has two errors in it! 这段代码中有两个错误!

memcpy(&profile.friendly_name, &string, 16); // Wrong!

First of all, &string is wrong. 首先, &string是错误的。 It should be string , because string is a pointer to the string data you want to copy. 它应该是string ,因为string是指向要复制的字符串数据的指针。 If you copy &string , you will get a pointer and some random bits of stack data copied instead. 如果你复制&string ,你会得到一个指针,而是复制一些随机的堆栈数据。 In other words, you'll get garbage. 换句话说,你会得到垃圾。

Secondly, 16 is wrong. 其次,16是错的。 You can only copy 16 bytes if you know that string points to at least 16 bytes of data. 如果您知道该string指向至少16个字节的数据,则只能复制16个字节。 This will cause a segmentation fault (crash your program, hard) if string is less than 16 bytes the following data in memory is not readable. 如果string小于16个字节,则会导致分段错误(程序崩溃),内存中的后续数据不可读。 It might not crash today, but maybe it will crash next week, and you'll have forgotten all about it? 它今天可能不会崩溃,但也许它会在下周崩溃,你会忘记它的一切吗?

It's wrong, don't pass 16 unless you know the source is at least 16 bytes long. 这是错误的,除非你知道源至少有16个字节长,否则不要传递16。

memcpy() should work fine, but strcpy() will work fine too. memcpy()应该可以正常工作,但strcpy()也可以正常工作。 You just need to make sure that profile.friendly_name is big enough to hold what you're copying into it. 您只需要确保profile.friendly_name足够大,可以保存您正在复制的内容。

Have you read the doc? 你读过这份文件吗? memcpy will work, but you pass in the number of bytes to copy. memcpy可以工作,但你传入要复制的字节数。 It will copy the number of bytes you specify, irrelevant of a NULL. 它将复制您指定的字节数,与NULL无关。 strcpy you don't pass the length, it will copy bytes up to and including the first NULL. strcpy你不传递长度,它会复制字节,包括第一个NULL。

http://www.cplusplus.com/reference/cstring/memcpy/ http://www.cplusplus.com/reference/cstring/memcpy/

http://www.cplusplus.com/reference/cstring/strcpy/ http://www.cplusplus.com/reference/cstring/strcpy/

//I have a non-null NSString called _friendly_name.
const char *string = [_friendly_name UTF8String];
//profile.friendly is a utf-8 null-terminated string  : char [17] ??
memcpy(profile.friendly_name, string, 16);
profile.friendly_name[16]='\0';

EDIT: Yes, exactly. 编辑:是的,确切地说。 Adding a NULL at ende. 在ende处添加NULL Actually it could be better to initialize to all 0 before copying. 实际上,在复制之前初始化为全0可能更好。 strcpy will not work if _friendly_name don't have a '\\0' before position 16. strncpy will be fine. strcpy ,如果将无法正常工作_friendly_name没有'\\0'位置之前16 strncpy将被罚款。

EDIT2: EDIT2:

Some problem arised why we dont have all the needed information: 出现了一些问题,为什么我们没有所有需要的信息:

1- You need an NULL-terminated string of length 16 (16 character+0 as in char var[17]; ) or you need a 16 byte field terminated witch NULL as in char var[16]; 1-您需要一个以NULL结尾的长度为16的字符串(16个字符+ 0,如char var[17]; )或者您需要一个16字节的字段终止,如char var[16]; ?

2- what is the desred "error" management: if the original string is larged than "16" we just truncate it, or we trow an error? 2-什么是desred“错误”管理:如果原始字符串大于“16”我们只是截断它,或者我们扔错了?

Assuming you need a field of 16 bytes and a truncate string you can use: 假设您需要一个16字节的字段和一个截断字符串,您可以使用:

strncpy(profile.friendly_name, string, 15);
profile.friendly_name[15]='\0';

EDIT3: EDIT3:

Also... to truncate have to be made carefully: we dont want to truncate a multibyte character... 另外......必须谨慎地截断:我们不想截断多字节字符...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM