gpt4 book ai didi

ios - NSLogv C 字符串编码

转载 作者:行者123 更新时间:2023-12-02 10:33:13 26 4
gpt4 key购买 nike

我使用 NSLogv 编写了一个小型日志记录包装器:

void MyLog(const char* format, ...) {
va_list vargs;
va_start(vargs, format);
NSString* formatStr = [NSString stringWithUTF8String:format];
NSLogv(formatStr, vargs);
va_end(vargs);
}

我可以这样使用:

MyLog("%d - %s", 123, "ABCD");

我遇到的问题是当我使用标准 ASCII 范围之外的字符时:

MyLog("%d - %s", 123, "АБВГ");

NSLogv 无法正确编码这些字符:

2019-10-01 11:10:30.890346+0300 TestApp[86349:7051788] 123 - –ê–ë–í–ì

在保持辅助方法的可变参数签名的同时对这些字符进行编码的正确方法是什么?

附注在 X86_64 模拟器和 ARM64 设备

上进行了尝试

如果我将 C 字符串转换为 UTF16,那么它会按预期工作:

std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
std::u16string value16 = convert.from_bytes("АБВГ");
MyLog("%d - %S", 123, value16.c_str());

最佳答案

您发现了 Objective-C 中格式化的一个奇怪“功能”,应该访问 Apple's Feedback Assistant并报告。

所以这是怎么回事?嗯,它与可变参数函数完全无关,也与 NSLogv 本身无关。相反,它与底层 Objective-C 格式化代码有关,其中 NSLogNSLogvstringWithFormat:et al 使用和格式字符串本身的类型...

这是“功能”的简单演示:

- (void)demo
{
char *sample = "АБВГ"; // This will be UTF-8 encoded

// use %p to show address, %s to show string, \n as printf doesn't add one
char *cFormat = "%p - %s\n";
NSString *nsFormat = @"%p - %s\n"; // produces an __NSCFConstantString
NSString *convertedFormat = [NSString stringWithUTF8String:cFormat]; // produces an __NSCFString

printf(cFormat, sample, sample); // works
NSLog(convertedFormat, sample, sample); // fails with __NSCFString
NSLog(nsFormat, sample, sample); // works with __NSCFConstantString

NSLog(@"formats equal: %s", [convertedFormat isEqualToString:nsFormat] ? "yes" : "no"); // __NSCFString & __NSCFConstantString are equal
}

运行它,控制台将显示如下内容:

0x1000013f8 - АБВГ
2019-10-01 10:25:48.222537+0100 demo[8435:1431874] 0x1000013f8 - –ê–ë–í–ì

2019-10-01 10:25:48.222560+0100 demo[8435:1431874] 0x1000013f8 - АБВГ
2019-10-01 10:25:48.222582+0100 demo[8435:1431874] formats equal: yes

因此,C 库 printf 可以工作,具有常量 NSString 格式的 NSLog 也可以工作,但是 char * 转换而来的 NSString 格式的 NSLog 则不然,但后两种格式比较相等...还要注意,在失败的情况下 NSLog 添加额外的换行符。

错误的输出 –ê–ë–í–ì 与 Xcode 为字符串的内存字节显示的参数字符串的解释相同。因此,格式字符串的基础类型决定了参数字符串的基础字节如何解释...

这样一个奇怪的“功能”让人怀疑它是否是出于某种原因而设计的,或者我们是否错过了显而易见的事情......也许其他人可以启发我们,但除非他们这样做,否则让我们称其为(奇怪的)错误!

解决方法

正如上面的演示所示,使用 C 库格式函数是可行的,因此,如果您愿意在每个大纲上丢失 NSLog 的序言,您可以在函数中使用其中一个:

void MyLog(const char *format, ...)
{
va_list vargs;
va_start(vargs, format);
vprintf(format, vargs);
va_end(vargs);
}

如果您希望保留 NSLog 的输出,您可以使用 C 库的 stringWithFormat: 等效项之一,这是动态分配的函数版本格式化 C 字符串所需的空间,然后将其释放(ARC 不会为您执行此操作!):<​​/p>

void MyLog(const char *format, ...)
{
va_list vargs;
va_start(vargs, format);
char *output;
vasprintf(&output, format, vargs);
NSLog(@"%s", output);
free(output);
va_end(vargs);
}

该“功能”在最新的 Xcode 11 和 macOS Catalina Beta 中仍然存在,因此请前往 Apple's Feedback Assistant 报告该问题。 .

HTH

关于ios - NSLogv C 字符串编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58180594/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com