有没有办法在 C 的预处理器或编译时检测 u8"" 文字?

Is there a way to detect u8"" literals at preprocessor or compile time in C?

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

由于涉及不同的类型,可以使用 _Generic() 表达式来区分不同大小的文字。遗憾的是,原生 "quoted literals"u8"quoted literals."

之间没有大小和类型差异

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

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

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

您可以使用 _Generic 然后做一些预处理器技巧来区分。首先是 _Generic 部分,在本例中我将 return 用于打印的字符串:

#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")

这个宏只是检查预处理器标记中的第一个字符是否是 "。它可以做得更高级一点,并寻找 '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