C++与C宏字符串连接的区别

huangapple go评论76阅读模式
英文:

C++ vs C Macro string concatenation difference

问题

我尝试编写一个类似以下的宏:
来自链接
我将相同的规则应用于我的软件,但没有成功。
我注意到C和C++之间有一些差异,但我不明白为什么,宏是预处理器的工作!
我还注意到,将来自枚举器的值传递给宏时存在一些差异。

#include <stdio.h>
#define CONCAT(string) "start"string"end"
int main(void) 
{
    printf(CONCAT("-hello-"));
    return 0;
}

报告的链接用于在线尝试代码在ideone上的演示链接允许选择不同的语言
C没问题,但切换到C++不起作用。
还有,在我的IDE Visual Studio Code(MinGw C++)中不起作用。

我的最终目标是编写一个宏,以参数化printf()函数,用于虚拟控制台应用程序,使用一些转义码。我尝试在宏连接中添加#,似乎可以工作,但如果我将枚举器传递给宏,我会得到意外的结果。代码如下:

#include <stdio.h>
#define def_BLACK_TXT 30
#define def_Light_green_bck 102

#define CSI "\e["
#define concat_csi(a, b) CSI #a ";" #b "m"
#define setTextAndBackgColor(tc, bc) printf(concat_csi(bc, tc))

enum VtColors { RESET_COLOR = 0, BLACK_TXT = 30, Light_green_bck = 102 };

int main(void){
    setTextAndBackgColor(30, 102);
    printf("\r\n");
    setTextAndBackgColor(def_BLACK_TXT , def_Light_green_bck );
    printf("\r\n");
    setTextAndBackgColor(VtColors::BLACK_TXT , VtColors::Light_green_bck );
    printf("\r\n");
    printf("\e[102;30m");//  <<---   this is the expected result of macro expansion
}

//and the output is : ( in the line 3 seems preprocessor don't resolve enum (the others line are ok) )
[102;30m 
[102;30m 
[VtColors::Light_green_bck;VtColors::BLACK_TXTm
[102;30m

显然,我希望将枚举器用作参数...(否则我将更改为#define)。

但我很好奇为什么会发生这种情况,以及为什么从C切换到C++时预处理器会有差异。

如果有人知道解决方法,非常感谢。

英文:

I try to write a macro like following:
taken from link
and I apply same rule to my software whit out success.
I notice some difference from C and C++, but I don't understand why, the macro are preprocessor job !
also I notice some difference passing to the macro the values coming from an enumerators.

#include <stdio.h>
#define CONCAT(string) "start"string"end"
int main(void) 
{
    printf(CONCAT("-hello-"));
    return 0;
}

the reported link used to try online the code link to a demo on ideone allow selection of different language
C is ok but changing to C++ it doesn't work.
Also in my IDE Visual Studio Code (MinGw C++) doesn't work.

My final target is write a macro to parametrize printf() function, for Virtual Console application using some escape codes. I try to add # to the macro concatenation and seems work but in case I pass an enumerator to the macro I have unexpected result. the code is :

#include <stdio.h>
#define def_BLACK_TXT 30
#define def_Light_green_bck 102

#define CSI "\e["
#define concat_csi(a, b) CSI #a ";" #b "m"
#define setTextAndBackgColor(tc, bc) printf(concat_csi(bc, tc))

enum VtColors { RESET_COLOR = 0, BLACK_TXT = 30, Light_green_bck = 102 };

int main(void){
    setTextAndBackgColor(30, 102);
    printf("\r\n");
    setTextAndBackgColor(def_BLACK_TXT , def_Light_green_bck );
    printf("\r\n");
    setTextAndBackgColor(VtColors::BLACK_TXT , VtColors::Light_green_bck );
    printf("\r\n");
    printf("\e[102;30m");//  <<---   this is the expected result of macro expansion
}

//and the output is : ( in the line 3 seems preprocessor don't resolve enum (the others line are ok) )
[102;30m 
[102;30m 
[VtColors::Light_green_bck;VtColors::BLACK_TXTm
[102;30m

Obviously I want use enumerators as parameter... (or I will change to #define).

But I'm curious to understand why it happens, and why there is difference in preprocessor changing from C to C++.

If anyone know the solution, many thanks.

答案1

得分: 1

在这里似乎存在一些编译器的分歧。

MSVC 将其编译为 C++而没有任何问题

gcc 则产生了一个编译错误

编译错误涉及到一个名为“用户自定义字面值”的 C++ 特性,其中语法 “something”后缀 被解析为一个用户定义的字面值(假设此用户定义的字面值已被正确声明)。

由于预处理阶段应该发生在编译阶段之前,我得出结论认为编译错误是编译器的一个错误。

请注意,添加一些空白字符会产生相同的结果,无论是将其编译为 C 还是 C++(并且使得 gcc 满意):

#define CONCAT(string) "start" string "end"

编辑:自 C++11 起,用户自定义字面值被认为是不同的标记

> 第三阶段
>
> 1) 源文件被分解成注释、空白字符序列(空格、水平制表符、换行符、垂直制表符和换页符)以及预处理令牌,它们包括:
>
> a) 头文件名称,如 <iostream> 或 "myfile.h"
>
> b) 标识符
>
> c) 预处理数字
>
> d) 字符和字符串字面值,包括用户定义的字面值(自 C++11 起)

我强调了这一点。

这发生在第四阶段之前:预处理器执行之前,因此在此处出现编译错误是正确的结果。"start"string,在没有间隔空白的情况下,会被解析为一个用户定义的字面值,在预处理阶段之前。

英文:

There appears to be some compiler disagreement here.

MSVC compiles it as C++ without any issues.

gcc produces a compilation error.

The compilation error references a C++ feature called "user-defined literals", where the syntax &quot;something&quot;suffix gets parsed as a user-defined literal (presuming that this user-defined literal gets properly declared).

Since the preprocessor phase should be happening before the compilation phase, I conclude that the compilation error is a compiler bug.

Note that adding some whitespace produces the same result whether it gets compiled as C or C++ (and makes gcc happy):

#define CONCAT(string) &quot;start&quot; string &quot;end&quot;

EDIT: as of C++11, user-defined literals are considered to be distinct tokens:

> Phase 3
>
> 1) The source file is decomposed into comments, sequences of
> whitespace characters (space, horizontal tab, new-line, vertical tab,
> and form-feed), and preprocessing tokens, which are the following:
>
> a)
> header names such as <iostream> or "myfile.h"
>
> b) identifiers
>
> c)
> preprocessing numbers d) character and string literals , including
> user-defined (since C++11)

emphasis mine.

This occurs before phase 4: preprocessor execution, so a compilation error here is the correct result. &quot;start&quot;string, with no intervening whitespace, gets parsed as a user-defined literal, before the preprocessor phase.

答案2

得分: -1

// 要总结的行为如下:(请参见代码中的注释)
```c
#include <stdio.h>
#define CONCAT_1(string) "start"#string"end"
#define CONCAT_2(string) "start"string"end"
#define CONCAT_3(string) "start" string "end"
int main(void) 
{
    printf(CONCAT_1("-hello-"));      // 错误,插入了双引号
    printf("\r\n");
    printf(CONCAT_1(-hello-));        // 正确,但没有引号
    printf("\r\n");
#if false
    printf(CONCAT_2("-hello-"));   // 编译错误
    printf("\r\n");
#endif
    printf(CONCAT_3("-hello-"));     // 正确
    printf("\r\n");
    printf("start" "-hello-" "end");    // 正确
    printf("\r\n");
    printf("start""-hello-""end");      // 正确
    printf("\r\n");
    return 0;
}
output:
start"-hello-"end   <<<--- 错误,插入了双引号
start-hello-end
start-hello-end
start-hello-end
start-hello-end

<details>
<summary>英文:</summary>

to summarize the behavioral is the following: (see comment in the code)

#include <stdio.h>
#define CONCAT_1(string) "start"#string"end"
#define CONCAT_2(string) "start"string"end"
#define CONCAT_3(string) "start" string "end"
int main(void)
{
printf(CONCAT_1("-hello-")); // wrong insert double quote
printf("\r\n");
printf(CONCAT_1(-hello-)); // OK but is without quote
printf("\r\n");
#if false
printf(CONCAT_2("-hello-")); // compiler error
printf("\r\n");
#endif
printf(CONCAT_3("-hello-")); // OK
printf("\r\n");
printf("start" "-hello-" "end"); // OK
printf("\r\n");
printf("start""-hello-""end"); // OK
printf("\r\n");
return 0;
}
output:
start"-hello-"end <<<--- wrong insert double quote
start-hello-end
start-hello-end
start-hello-end
start-hello-end


</details>



huangapple
  • 本文由 发表于 2023年1月9日 07:58:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/75052149.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定