#include <iostream>
#define help(a) #a
#define xhelp(a) help(a)
#define glue(a,b) a##b
#define xglue(a,b) glue(a,b)
#define HIGHLOW "hello"
#define LOWLOW ",world"
int main()
{
std::cout<<xhelp(xglue(HIGH,LOW))<<std::endl;
return 0;
}
here is my test code. I want to know the spread of the MACOR xglue(HIGH,LOW).
For me, i think the result is "hello"
but i learn from one website, the result is "hello, world".
I am really confused with it.
the result of my code is aslo "hello".
Is there anyone could help me with it?
I think the xgule(HIGH,LOW)=glue(HIGH,LOW)=HIGHLOW="hello"
THe website show that xglue(HIGH,LOW)=glue(HIGH,LOW",world")="hello, world"
First of all, there is no recursive macro.
Most work in the example is performed by the two preprocessor operators # and ##.
# is a unary operator that turns its argument into a string literal.
## is a binary operator that pastes two tokens together to form one single token.
The easiest way to check what a given preprocessor code expands to is actually to run the preprocessor. The g++ compiler has a -E option to do exactly that.
# Assuming your file is saved as code.cpp
$ g++ -E code.cpp
... lots of output ...
int main()
{
std::cout<<"\"hello\""<<std::endl;
return 0;
}
Related
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.
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
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 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.
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
I am using ## (Token-Pasting Operator) to form a function call.
According to my understanding, a simple example may look like this.
#include <iostream>
#define CALL(x) Func_##x##()
void Func_foo() { std::cout << "Hi from foo()." << std::endl; }
int main() {
std::cout << "Hello World!" << std::endl;
CALL(foo);
return 0;
}
I compiled this code with g++ -std=c++14 -O3 test.cc. The G++ version is 7.3.1.
It returns the following error.
error: pasting "Func_foo" and "(" does not give a valid preprocessing token
If I change the macro to #define CALL(x) Func_##x() (delete the second ##), the error will be solved.
Why the second ## is redundant? The ## connects strings and substitutes with macro arguments if possible. For example, I change the function name to Func_foo1(), then the macro should be #define CALL(x) Func_##x##1(). This works as my expected.
I am a little confused about the macro definition #define CALL(x) Func_##x().
A token is the smallest element of a C++ program that is meaningful to the compiler.
The ## Token-pasting operator does not concatenate arbitrary printable characters. It concatenates two tokens into one token.
Why the second ## is redundant?
Because concatenating Func_foo and () does not produce a single token.
What does this line mean? Especially, what does ## mean?
#define ANALYZE(variable, flag) ((Something.##variable) & (flag))
Edit:
A little bit confused still. What will the result be without ##?
A little bit confused still. What will the result be without ##?
Usually you won't notice any difference. But there is a difference. Suppose that Something is of type:
struct X { int x; };
X Something;
And look at:
int X::*p = &X::x;
ANALYZE(x, flag)
ANALYZE(*p, flag)
Without token concatenation operator ##, it expands to:
#define ANALYZE(variable, flag) ((Something.variable) & (flag))
((Something. x) & (flag))
((Something. *p) & (flag)) // . and * are not concatenated to one token. syntax error!
With token concatenation it expands to:
#define ANALYZE(variable, flag) ((Something.##variable) & (flag))
((Something.x) & (flag))
((Something.*p) & (flag)) // .* is a newly generated token, now it works!
It's important to remember that the preprocessor operates on preprocessor tokens, not on text. So if you want to concatenate two tokens, you must explicitly say it.
## is called token concatenation, used to concatenate two tokens in a macro invocation.
See this:
Macro Concatenation with the ## Operator
One very important part is that this token concatenation follows some very special rules:
e.g. IBM doc:
Concatenation takes place before any
macros in arguments are expanded.
If the result of a concatenation is a
valid macro name, it is available for
further replacement even if it
appears in a context in which it
would not normally be available.
If more than one ## operator and/or #
operator appears in the replacement
list of a macro definition, the order
of evaluation of the operators is not
defined.
Examples are also very self explaining
#define ArgArg(x, y) x##y
#define ArgText(x) x##TEXT
#define TextArg(x) TEXT##x
#define TextText TEXT##text
#define Jitter 1
#define bug 2
#define Jitterbug 3
With output:
ArgArg(lady, bug) "ladybug"
ArgText(con) "conTEXT"
TextArg(book) "TEXTbook"
TextText "TEXTtext"
ArgArg(Jitter, bug) 3
Source is the IBM documentation. May vary with other compilers.
To your line:
It concatenates the variable attribute to the "Something." and adresses a variable which is logically anded which gives as result if Something.variable has a flag set.
So an example to my last comment and your question(compileable with g++):
// this one fails with a compiler error
// #define ANALYZE1(variable, flag) ((Something.##variable) & (flag))
// this one will address Something.a (struct)
#define ANALYZE2(variable, flag) ((Something.variable) & (flag))
// this one will be Somethinga (global)
#define ANALYZE3(variable, flag) ((Something##variable) & (flag))
#include <iostream>
using namespace std;
struct something{
int a;
};
int Somethinga = 0;
int main()
{
something Something;
Something.a = 1;
if (ANALYZE2(a,1))
cout << "Something.a is 1" << endl;
if (!ANALYZE3(a,1))
cout << "Somethinga is 0" << endl;
return 1;
};
This is not an answer to your question, just a CW post with some tips to help you explore the preprocessor yourself.
The preprocessing step is actually performed prior to any actual code being compiled. In other words, when the compiler starts building your code, no #define statements or anything like that is left.
A good way to understand what the preprocessor does to your code is to get hold of the preprocessed output and look at it.
This is how to do it for Windows:
Create a simple file called test.cpp and put it in a folder, say c:\temp.
Mine looks like this:
#define dog_suffix( variable_name ) variable_name##dog
int main()
{
int dog_suffix( my_int ) = 0;
char dog_suffix( my_char ) = 'a';
return 0;
}
Not very useful, but simple. Open the Visual studio command prompt, navigate to the folder and run the following commandline:
c:\temp>cl test.cpp /P
So, it's the compiler your running (cl.exe), with your file, and the /P option tells the compiler to store the preprocessed output to a file.
Now in the folder next to test.cpp you'll find test.i, which for me looks like this:
#line 1 "test.cpp"
int main()
{
int my_intdog = 0;
char my_chardog = 'a';
return 0;
}
As you can see, no #define left, only the code it expanded into.
According to Wikipedia
Token concatenation, also called token pasting, is one of the most subtle — and easy to abuse — features of the C macro preprocessor. Two arguments can be 'glued' together using ## preprocessor operator; this allows two tokens to be concatenated in the preprocessed code. This can be used to construct elaborate macros which act like a crude version of C++ templates.
Check Token Concatenation
lets consider a different example:
consider
#define MYMACRO(x,y) x##y
without the ##, clearly the preprocessor cant see x and y as separate tokens, can it?
In your example,
#define ANALYZE(variable, flag) ((Something.##variable) & (flag))
## is simply not needed as you are not making any new identifier. In fact, compiler issues "error: pasting "." and "variable" does not give a valid preprocessing token"
In a .cpp, I want to output a file to a directory created at compile time (determined by the time of compilation). I have passed this value via -DCOMPILETIME=$(stuff about time) in my makefile. I would like to pass the value stored in COMPILETIME to sprintf so I can create a filepath string to eventually use to place my output file.
I have tried:
#define str(x) #x
sprintf(filepath,"\"%s\file\"",str(COMPILETIME));
as well as
#define str(x) #x
#define strname(name) str(name)
sprintf(filepath,"\"%s\file\"",strname(COMPILETIME));
but I only ever get
"COMPILETIME/file"
as output.
Your macros are fine. Here's a test program:
#include <stdio.h>
#define str(x) #x
#define strname(name) str(name)
int main()
{
printf("\"%s/file\"\n",strname(COMPILETIME));
return 0;
}
Build command:
cc -Wall -o soc soc.c
Output:
"COMPILETIME/file"
Build command:
cc -Wall -o soc soc.c -DCOMPILETIME=abcd
Output:
"abcd/file"
Tested under gcc 4.9.2.
The problem you are facing with fopen could be related to:
sprintf(filepath,"\"%s\file\"",strname(COMPILETIME));
^^^^
Make that
sprintf(filepath,"\"%s\\file\"",strname(COMPILETIME));
^^^^
Otherwise, you are escaping the character f, which does nothing. You should also be able to use a forward slash instead of a backward slash.
sprintf(filepath,"\"%s/file\"",strname(COMPILETIME));
^^^^
I am wondering if it is possible in C++11/14 to actually read files at compile time. For example the following code will only compile if it can successfully read the file.
constexpr std::string shader_source = load("~/foo.glsl");
Do you think this could be possible?
I know that I could do this with some custom tool when building my application.
Building on teivaz's idea, I wonder if the usual "stringize after expansion" trick will work:
#define STRINGIZE(...) #__VA_ARGS__
#define EXPAND_AND_STRINGIZE(...) STRINGIZE(__VA_ARGS__)
constexpr std::string shader_source = EXPAND_AND_STRINGIZE(
#include "~/.foo.glsl"
);
Still, I would go for a conventional extern const char[] declaration resolved to the content by the linker. The article "Embedding a File in an Executable, aka Hello World, Version 5967" has an example:
# objcopy --input binary \
--output elf32-i386 \
--binary-architecture i386 data.txt data.o
Naturally you should change the --output and --binary-architecture commands to match your platform. The filename from the object file ends up in the symbol name, so you can use it like so:
#include <stdio.h>
/* here "data" comes from the filename data.o */
extern "C" char _binary_data_txt_start;
extern "C" char _binary_data_txt_end;
main()
{
char* p = &_binary_data_txt_start;
while ( p != &_binary_data_txt_end ) putchar(*p++);
}
#define STR(x) #x
const char* a =
{
#include "foo.glsl"
};
and foo.glsl should enclose its content in
STR(
...
)
upd. This will properly handle commas
#define STRINGIFY(...) #__VA_ARGS__
#define STR(...) STRINGIFY(__VA_ARGS__)
I have done something like this. See if this will give you what you want.
Add a command line option to the program that checks for the existence and validity of the input file.
That option should exit the program with an error code if the file does not exist, or is not valid.
In your make file, add a call to the program (using that command line option), as the final build step.
Now when you build the program, you will get an error if the proper files are not available or not valid.
This is my C solution, but for C++ is the same. Stringify #define does not work with #include in my case with modern compilers, so you can use raw string literals inside your file to embed the content inside a string at compile time.
test.c:
#include <stdio.h>
const char *text = {
#include "test.dat"
};
int main() {
printf("%s\n", text);
}
test.dat:
R"(This is a line.
This is another line...)"