首页 > 解决方案 > 有没有办法在 C 中的预处理器或编译时检测 u8"" 文字?

问题描述

C11 现在提供了几种字符串文字:

由于所涉及的类型不同,可以使用_Generic()表达式区分不同大小的文字。"quoted literals"可悲的是,原生和原生之间没有大小或类型差异u8"quoted literals."

我想知道是否可以使用预处理器魔法,但似乎 GCC 要么将u8"text"视为不可分割的令牌,要么u8在早期阶段吃掉 。无论如何,我无法使用宏获取“u8”前缀。:-(

所以,我想知道:有没有什么方法可以在“不知道”的情况下区分本机编码文字和 UTF-8 编码文字?

上下文是我想要将传递的字符串智能地转换为 UTF-8 的库代码。如果我可以将调用包装在一个确定是否需要对字符串进行转码的宏中,那就太好了。(否则,当然,我必须依赖用户。你知道他是个白痴。)

标签: cstring-literalsc11

解决方案


您可以使用_Generic然后做一些预处理器技巧来区分。首先是_Generic部分,在这种情况下我返回一个用于打印的字符串:

#define LITERAL_TYPE(s)            \
  _Generic((s),                    \
           char*: U8_TYPE(s),      \
           wchar_t*: "wchar_t",    \
           char16_t*: "char16_t",  \
           char32_t*: "char32_t")

然后是U8_TYPE宏:

#define U8_TYPE(s) (#s[0]=='\"'? "old school":"u8")

该宏仅检查预处理器标记中的第一个字符是否为 a "。它可以做得更高级一些,'u'并且'8'还可以通过一些&&检查来查找,尽管在这种情况下你也必须检查结尾'"',这样你就不会越界访问。

测试代码:

#include <stdio.h>
#include <wchar.h>
#include <uchar.h>

#define U8_TYPE(s) (#s[0]=='\"'? "old school":"u8")

#define LITERAL_TYPE(s)            \
  _Generic((s),                    \
           char*: U8_TYPE(s),      \
           wchar_t*: "wchar_t",    \
           char16_t*: "char16_t",  \
           char32_t*: "char32_t")

int main(void)
{
   puts(LITERAL_TYPE("hello"));
   puts(LITERAL_TYPE(L"hello"));
   puts(LITERAL_TYPE(u8"hello"));
   puts(LITERAL_TYPE(u"hello"));
   puts(LITERAL_TYPE(U"hello"));
}

输出:

old school
wchar_t
u8
char16_t
char32_t

推荐阅读