3

我正在努力实现一些低级文件写入,其中文件格式特定于每一位。我需要将一个字符串从一个NSString长度为 16 的以空字符结尾的字符串复制(根据 Xcode,这是不可分配的)。在谈到 时,我是一个完全的n00bc,并且想确保我正确理解这一点。这就是我目前正在做的事情:

//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);

这尚未经过测试,但我想确保这会奏效。这会提供我期望的行为吗?或者我应该以不同的方式复制字符串(例如strcpy)?

4

4 回答 4

4

您可以使用memcpy()or strcpy(),但您必须自己检查边界,并且代码中还有其他错误。

所以,我认为你想将一个 NSString 复制到一个char[16]数组中。您可以使用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';

如果你想使用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';

代码中的错误

这段代码有两个错误!

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

首先,&string是错误的。应该是string,因为string它是指向要复制的字符串数据的指针。如果你 copy &string,你会得到一个指针和一些随机的堆栈数据位。换句话说,你会得到垃圾。

其次,16 是错误的。如果您知道这string指向至少 16 个字节的数据,则只能复制 16 个字节。string如果小于 16 个字节,内存中的以下数据不可读,这将导致分段错误(使您的程序崩溃) 。它今天可能不会崩溃,但也许它会在下周崩溃,你会忘记这一切吗?

这是错误的,除非您知道源至少有 16 个字节长,否则不要传递 16。

于 2013-02-18T23:11:02.977 回答
3

memcpy() 应该可以正常工作,但 strcpy() 也可以正常工作。您只需要确保 profile.friendly_name 足够大以容纳您要复制的内容。

于 2013-02-18T22:52:57.267 回答
2

你读过文档吗?memcpy 将起作用,但您传递要复制的字节数。它将复制您指定的字节数,与 NULL 无关。strcpy 你不传递长度,它将复制字节直到并包括第一个 NULL。

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

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

于 2013-02-18T22:59:23.307 回答
0
//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';

编辑:是的,完全正确。在结束时添加一个NULL。实际上,0在复制之前对 all 进行初始化可能会更好。strcpy如果_friendly_name没有'\0'前位置 16strncpy将无法工作。会很好。

编辑2:

出现了一些问题,为什么我们没有所有需要的信息:

1-您需要一个长度为 16 的以 NULL 结尾的字符串(如中的 16 个字符 + 0 char var[17];),或者您需要一个以 NULL 结尾的 16 字节字段,如中char var[16];

2-什么是desred“错误”管理:如果原始字符串大于“16”,我们只是截断它,或者我们抛出一个错误?

假设您需要一个 16 字节的字段和一个可以使用的截断字符串:

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

编辑3:

另外......必须小心截断:我们不想截断多字节字符......

于 2013-02-18T22:55:24.980 回答