首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >通过标记连接创建包含通用字符名称的标识符

通过标记连接创建包含通用字符名称的标识符
EN

Stack Overflow用户
提问于 2016-04-22 15:42:46
回答 1查看 697关注 0票数 20

我写了这段代码,它通过标记连接创建包含通用字符名称的标识符。

代码语言:javascript
复制
//#include <stdio.h>
int printf(const char*, ...);

#define CAT(a, b) a ## b

int main(void) {
    //int \u306d\u3053 = 10;
    int CAT(\u306d, \u3053) = 10;

    printf("%d\n", \u306d\u3053);
    //printf("%d\n", CAT(\u306d, \u3053));

    return 0;
}

此代码在gcc 4.8.2 with -fextended-identifiers optiongcc 5.3.1上运行良好,但不能在clang 3.3上运行,并显示错误消息:

代码语言:javascript
复制
prog.c:10:17: error: use of undeclared identifier 'ねこ'
        printf("%d\n", \u306d\u3053);
                       ^
1 error generated.

和本地clang (Apple LLVM版本7.0.2 (clang-700.1.81)),并显示错误消息:

代码语言:javascript
复制
$ clang -std=c11 -Wall -Wextra -o uctest1 uctest1.c
warning: format specifies type 'int' but the argument has type
      '<dependent type>' [-Wformat]
uctest1.c:10:17: error: use of undeclared identifier 'ねこ'
        printf("%d\n", \u306d\u3053);
                       ^
1 warning and 1 error generated.

当我使用-E选项让编译器输出带有展开宏的代码时,gcc 5.3.1发出了这样的消息:

代码语言:javascript
复制
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "main.c"

int printf(const char*, ...);



int main(void) {

 int \U0000306d\U00003053 = 10;

 printf("%d\n", \U0000306d\U00003053);


 return 0;
}

本地clang发出以下命令:

代码语言:javascript
复制
# 1 "uctest1.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 326 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "uctest1.c" 2

int printf(const char*, ...);



int main(void) {

 int \u306d\u3053 = 10;

 printf("%d\n", ねこ);


 return 0;
}

如您所见,在printf()中声明和使用的标识符在gcc的输出中匹配,但在clang的输出中不匹配。

我知道通过标记连接创建通用字符名称会调用未定义的行为。

引用自N1570 5.1.1.2转换阶段:

如果标记连接(6.10.3.3)生成的字符序列与通用字符名称的语法匹配,则行为未定义。

我认为这个字符序列\u306d\u3053可能“匹配通用字符名称的语法”,因为它包含通用字符名称作为它的子字符串。我还认为“匹配”可能意味着通过连接产生的整个令牌代表一个通用字符名称,因此在此代码中不会调用这种未定义的行为。

在阅读PRE30-C. Do not create a universal character name through concatenation时,我发现了一条评论,说这种连接是允许的:

什么是被禁止的,通过连接创建一个新的UCN。喜欢做某事

分配(\u00010401,a,b,4)

只要连接任何地方恰好包含UCN的内容就可以了。

以及显示a code example like this case (but with 4 characters)已被another code example替换的日志。

我的代码示例是否调用了一些未定义的行为(不限于通过标记连接生成通用字符名称来调用的行为)?或者这是clang中的一个bug?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-05 12:47:10

您的代码不会触发您提到的未定义行为,因为通用字符名称(6.4.3)不是由标记连接生成的。

并且,根据6.10.3.3,由于操作符##的左侧和右侧都是标识符,并且所产生的令牌也是有效的预处理令牌(也是标识符),所以##操作符本身不会触发未定义的行为。

在阅读了关于标识符(6.4.2,D.1,D.2)和通用字符名称(6.4.3)的描述后,我非常确定它更像是clang预处理器中的一个bug,它将令牌连接产生的标识符与普通标识符区别对待。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36787863

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档