英文:
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 "something"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) "start" string "end"
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. "start"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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论