我第一次使用Apple的Unified Logging,并取得了一些成功。但是,我无法使其与建议的%{timeval}.*P自定义格式说明符一起使用。

我的第一次尝试是:

struct timeval some_time;
// ... populate `some_time`
os_log_info(OS_LOG_DEFAULT, "a thing happened at %{timeval}.*P", some_time);

但是clang报告一个错误:field precision should have type 'int', but argument has type 'struct timeval'

我相信问题是clang不理解os_log的格式规则,如果我能弄清楚如何通过clang diagnostic push等抑制clang的错误,我会的。看起来底层宏OS_LOG_CALL_WITH_FORMAT似乎正在尝试这样做,但是没有运气。

我是否滥用timeval格式说明符?

这是Xcode 8.3.1的版本,我没有尝试过Xcode的早期版本。

最佳答案

TL; DR

工作代码

os_log_info(OS_LOG_DEFAULT, "a thing happened at %{timeval}.16P", &some_time);

要么
os_log_info(OS_LOG_DEFAULT, "a thing happened at %{timeval}.*P", (int)sizeof(some_time), &some_time);

这里的问题是格式定义中的通配符(*)代表int。因此,实际上%{timeval}。* P接受2个参数:int和指向timeval结构的指针。

不幸的是,这是非常糟糕的文档,甚至os_log用法的Apple Sample Code也没有这样的示例。

到目前为止,查看示例的最佳方法是研究LLVM源代码中的测试。
format-strings-oslog.m
__builtin_os_log_format(buf, "%d", i);
__builtin_os_log_format(buf, "%P", p); // expected-warning {{using '%P' format specifier without precision}}
__builtin_os_log_format(buf, "%.10P", p);
__builtin_os_log_format(buf, "%.*P", p); // expected-warning {{field precision should have type 'int', but argument has type 'void *'}}
__builtin_os_log_format(buf, "%.*P", i, p);
__builtin_os_log_format(buf, "%.*P", i, i); // expected-warning {{format specifies type 'void *' but the argument has type 'int'}}

07-28 14:08