Why is this macro generating a syntax error? - c++

So this is my code:
// Defines a tuple
#define __WINDOW__RESOLUTION__ 500, 200
// Seperate the tuple
#define __WINDOW__X__1(Width, Height) (Width)
#define __WINDOW__Y__1(Width, Height) (Height)
// Add another sort of indirection because my tuple is a macro
#define __WINDOW__X__(Macro) __WINDOW__X__1(Macro)
#define __WINDOW__Y__(Macro) __WINDOW__Y__1(Macro)
// These should be the final values 500 and 200
#define __WINDOW__RESOLUTION__X__ (__WINDOW__X__(__WINDOW__RESOLUTION__))
#define __WINDOW__RESOLUTION__Y__ (__WINDOW__Y__(__WINDOW__RESOLUTION__))
When i use the first macro where the final number should be something seems to go wrong:
std::cout << __WINDOW__RESOLUTION__X__ << std::endl; // Outputs 200 instead of 500
above line outputs the number 200, so the Y value instead of the X value
std::cout << __WINDOW__RESOLUTION__Y__ << std::endl; // ERR with macro underlined
this line won't even compile [ C2059, syntax error: ")" ]
Thank you for helping me Alex

For the record - I understand that your solution is "do not do this", but I still wanted to provide an answer for the original question.
In fact, I actually don't see anything wrong with your code. It actually works fine if you compile it with a basic test example like this one:
// Defines a tuple
#define __WINDOW__RESOLUTION__ 500, 200
// Seperate the tuple
#define __WINDOW__X__1(Width, Height) (Width)
#define __WINDOW__Y__1(Width, Height) (Height)
// Add another sort of indirection because my tuple is a macro
#define __WINDOW__X__(Macro) __WINDOW__X__1(Macro)
#define __WINDOW__Y__(Macro) __WINDOW__Y__1(Macro)
// These should be the final values 500 and 200
#define __WINDOW__RESOLUTION__X__ (__WINDOW__X__(__WINDOW__RESOLUTION__))
#define __WINDOW__RESOLUTION__Y__ (__WINDOW__Y__(__WINDOW__RESOLUTION__))
#include <iostream>
using namespace std;
int main() {
// your code goes here
std::cout << __WINDOW__RESOLUTION__X__ << std::endl;
std::cout << __WINDOW__RESOLUTION__Y__ << std::endl;
return 0;
}
It looks like your error may be related to the brackets in your last macro, though, so just removing them could possibly solve that, but again - this wasn't required for me (using gcc 5.4 under ubuntu):
// These should be the final values 500 and 200
#define __WINDOW__RESOLUTION__X__ __WINDOW__X__(__WINDOW__RESOLUTION__)
#define __WINDOW__RESOLUTION__Y__ __WINDOW__Y__(__WINDOW__RESOLUTION__)
It was previously also pointed out that double underscore __ followed by an upper-case letter is reserved, but it certainly didn't stop gcc from compiling this - maybe it would generate an error with stricter compile flags, though!

It seems to work fine when compiled with gcc4.9, but the problem might lie in that the compiler threads __WINDOW__RESOLUTION__ as a single parameter. For example, if you replace
#define __WINDOW__RESOLUTION__X__ (__WINDOW__X__(__WINDOW__RESOLUTION__))
with
#define __WINDOW__RESOLUTION__X__ (__WINDOW__X__(500, 200))
It will throw an error because __WINDOW__X__ expects only 1 parameter.
You can solve this by using ... and __VA_ARGS__ in your macro, which will forward any parameter that it receives:
#define __WINDOW__X__(...) __WINDOW__X__1(__VA_ARGS__)
#define __WINDOW__Y__(...) __WINDOW__Y__1(__VA_ARGS__)

Related

why can't compare string in #if expression in c++

i want to write code like this but i can't:
#define COLOR "red"
#define RED "red"
#define BLUE "blue"
int main()
{
// following code can't be compiled
#if (COLOR==RED)
cout<<"red"<<endl;
#endif
// following code can work
if(COLOR==RED)
cout<<"red"<<endl;
else
cout<<"notred"<<endl;
}
so how can i realize string compare in #if expression? or may be this is not possible?
BTW i know i can realize in other ways like following:
#define COLOR 1
#define RED 1
#define BLUE 2
// can be compiled and word correctly
#if(COLOR==RED)
cout<<"red"<<endl;
#endif
Because #if only works with integers
expression is a C expression of integer type, subject to stringent restrictions. It may contain...
see https://gcc.gnu.org/onlinedocs/gcc-3.0.1/cpp_4.html#SEC38
#include <iostream>
// internal functions, can be put into included header
#define TRUE 1
#define XEQUAL(a, b) a##_##b
#define EQUAL(a, b) XEQUAL(a, b)
#define XCUSTOMSTR(a) color_##a
#define CUSTOMSTR(a) XCUSTOMSTR(a)
#define XSTR(a) #a
#define STR(a) XSTR(a)
// define available colors
#define red_red TRUE
#define blue_blue TRUE
#define green_green TRUE
// optional custom names
#define color_green "grĂ¼n"
#define COLOR red
#define COLOR2 green
int main() {
#if EQUAL(COLOR, red)
std::cout << "my_"STR(COLOR)"_file.txt";
#endif
#if EQUAL(COLOR, COLOR2)
char filename[] = "my_"STR(COLOR2)"_file.txt";
std::cout << filename;
#endif
std::cout << CUSTOMSTR(green);
return 0;
}
The trick is to compare before making a string out of it.
The preprocessor can not process strings (except generate them), but it can process textual tokens!

How to call macro that uses token pasting?

I am trying to print ffmpeg version in a C++ program. I see that in the /libavutil/version.h there is AV_VERSION which should tell the version number in the format x.x.x.
As a test I used some random numbers as function parameters like this: std::string version = AV_VERSION(3,4,2);. The same error I get if I use LIBAVUTIL_VERSION_MAJOR, LIBAVUTIL_VERSION_MINOR and LIBAVUTIL_VERSION_MICRO from the file. That was actually my first try to print the version number.
The error I get is invalid suffix '.2' on floating constant or invalid suffix '.101' on floating constant if I try to print std::cout << AV_VERSION(LIBAVUTIL_VERSION_MAJOR,LIBAVUTIL_VERSION_MINOR,LIBAVUTIL_VERSION_MICRO) << std::endl;
I do understand that the preprocessor is thinking that the token is a float, hence the error. How do you actually use this type of macro funtion?
That macro is in the file I mentioned above, so it must be a way to call that macro function without giving an error, thinking that is a mature library, and I guess other libraries use something similar for printing version number.
Here is how AV_VERSION is defined in the header file and how I call it:
#define AV_VERSION_INT(a, b, c) ((a)<<16 | (b)<<8 | (c))
#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c
#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c)
#define AV_VERSION_MAJOR(a) ((a) >> 16)
#define AV_VERSION_MINOR(a) (((a) & 0x00FF00) >> 8)
#define AV_VERSION_MICRO(a) ((a) & 0xFF)
#define LIBAVUTIL_VERSION_MAJOR 57
#define LIBAVUTIL_VERSION_MINOR 9
#define LIBAVUTIL_VERSION_MICRO 101
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
LIBAVUTIL_VERSION_MINOR, \
LIBAVUTIL_VERSION_MICRO)
#define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \
LIBAVUTIL_VERSION_MINOR, \
LIBAVUTIL_VERSION_MICRO)
int main()
{
std::string version = AV_VERSION(3,4,2);
std::cout << AV_VERSION(LIBAVUTIL_VERSION_MAJOR,LIBAVUTIL_VERSION_MINOR,LIBAVUTIL_VERSION_MICRO) << std::endl;
return 0;
}
I coud've skip this error but as I'm trying to learn C++ I am pretty sure that I will find more of this type of macros so no point to avoid learning them now as I'm facing them.
Thanks in advance!
You need to use a stringize expansion. Because of how the preprocessor works, this involves two macros:
#define STR(x) #x
#define XSTR(x) STR(x)
The macro STR will take whatever parameter you give it and make that a string literal.
The macro XSTR will first expand its parameter x and the result will be the parameter to STR.
To illustrate:
STR(LIBAVUTIL_VERSION) will give "LIBAVUTIL_VERSION"
XSTR(LIBAVUTIL_VERSION) will give "57.9.101"
Demo according to your code:
int main()
{
std::string version1 = XSTR(LIBAVUTIL_VERSION);
std::string version2 = XSTR(AV_VERSION(3,4,2));
std::cout << version1 << "\n";
std::cout << version2 << "\n";
return 0;
}
Output:
57.9.101
3.4.2

Why does including <windows.h> result in "error: expected ')' before numeric constant" on an unrelated #define statement

Can anybody explain what is going wrong here? When I try to compile qtermwidget under MinGW-w64, and adding #include <windows.h> to source file BlockArray.cpp, I get the following compile error relating to #define BlockSize (1 << 12) in BlockArray.h:
In file included from E:/git/qtermwidget/lib/BlockArray.cpp:27:
E:/git/qtermwidget/lib/BlockArray.h:30:20: error: expected ')' before numeric constant
30 | #define BlockSize (1 << 12)
| ~^
Why is the addition of the windows.h header causing this error? Assuming I really want to add this header, can I change the #define BlockSize (1 << 12) in BlockArray.h somehow to not break the compile?
Thanks very much to Sam and busybee, I can confirm that there is a name conflict in winnt.h which is brought in via windows.h. It's a typedef using the 'BlockSize' name, rather than another preprocessor definition, however:
typedef struct _TAPE_SET_MEDIA_PARAMETERS {
ULONG BlockSize;
} TAPE_SET_MEDIA_PARAMETERS, *PTAPE_SET_MEDIA_PARAMETERS;
Changing the #define BlockSize (1 << 12) in BlockArray.h to a new name, e.g. #define LXQT_BlockSize (1 << 12) resolves the conflict.

How to define an array of strings and set its values in header files in C++?

In my program, I use constants defined through the #define directive in order to manage the program's logic. At the same time, if I need to print one of these values, I need some way to map these numbers with a string.
Here is a simplified version of what I'm attempting:
Header file: header.hpp
#ifndef HEADER_HPP
#define HEADER_HPP
#include <string>
#define CODE_0 0
#define CODE_1 1
#define CODE_2 2
#define CODE_3 3
std::string label[4];
label[CODE_0] = "label0";
label[CODE_1] = "label1";
label[CODE_2] = "label2";
label[CODE_3] = "label3";
#endif /* HEADER_HPP */
Main function: source.cpp
#include "header.hpp"
#include <iostream>
int main()
{
std::cout << "Start" << std::endl;
std::cout << "Code #" << CODE_1 << " has label '" << label[CODE_1] << "'" << std::endl;
std::cout << "End" << std::endl;
return 0;
}
However, this doesn't work. Here's the compiler output:
In file included from source.cpp:1:0:
header.hpp:12:1: error: 'label' does not name a type
label[CODE_0] = "label0";
^
header.hpp:13:1: error: 'label' does not name a type
label[CODE_1] = "label1";
^
header.hpp:14:1: error: 'label' does not name a type
label[CODE_2] = "label2";
^
header.hpp:15:1: error: 'label' does not name a type
label[CODE_3] = "label3";
^
I'm not sure why this is happening. It looks like this isn't the way to set the array's values. What would be the correct way?
Also, although it is a different question, what would be a better way to map these constant numeric values to their respective strings? Notice that I intend them to remain constant (both number and string).
You can initialize this array in header file without explicit assignment statements:
std::string label[4] =
{
"label0"
, "label1"
, "label2"
, "label3"
};
The better approach would be to get rid of it completely or at least make it class static variable and define in cpp file. Also it would be better to replace #define CODE_0 macroses with enumerator.

Expansion of C++ macro within macro to be concatenated

I have to let CS students modify a group number and then generate some stuff related to that number. I don't want students to modify much but only that one group number defined somewhere as
#define GROUP_NUM 0
However, I cannot find a way to generate the rest from that MACRO.
For example:
#include <iostream>
using namespace std;
// string troubles
#define STR(x) #x
#define XSTR(x) STR(x)
// the trouble
#define GROUP_NUM 0
#define CLASS_NAME Group GROUP_NUM
#define CLASS_STR XSTR(CLASS_NAME)
int main()
{
cout << "CLASS_NAME = " << CLASS_STR << endl;
return 0;
}
outputs sadly
CLASS_NAME = Group 0
Here the trouble is that I don't want that space between Group and 0 because I need to use CLASS_NAME to create some class out of it such as
class CLASS_NAME : public .... { ... }
I tried to use
#define CLASS_NAME Group##GROUP_NUM
but then GROUP_NUM doesn't get expanded and it outputs
CLASS_NAME = GroupGROUP_NUM
The only solution I have found is to define these CLASS_NAME and CLASS_STR as macro functions which are passed the group number as argument (on the call site, not in another macro!):
// the trouble
#define GROUP_NUM 0
#define CLASS_NAME(g) Group ## g
#define CLASS_STR(g) XSTR(CLASS_NAME(g))
int main()
{
cout << "CLASS_NAME = " << CLASS_STR(GROUP_NUM) << endl;
return 0;
}
Is there a better solution? Why doesn't the following get expanded?
#define CLASS_STR XSTR(CLASS_NAME(GROUP_NUM))
The definition of XSTR above seems to show that one can use chained macros, so I don't understand why it doesn't get expanded here.
Update:
The trick of the helper macro functions is the solution. However I'd like to clarify the solution:
how does the macro expansion trick work? does it fully expand directly or does it only do one round of expansion? (i.e. if I have imbricated macros, would it mean I need more than one layer of helper function?)
the expansion with ## is still somewhat mysterious to me
My full problem was involving the nori framework and especially this.
With that macro, i.e.
#define NORI_REGISTER_CLASS(cls, name) \
cls *cls ##_create(const PropertyList &list) { \
return new cls(list); \
} \
static struct cls ##_{ \
cls ##_() { \
NoriObjectFactory::registerClass(name, cls ##_create); \
} \
} cls ##__;
If I use NORI_REGISTER_CLASS(CLASS_NAME, "mystring"), it gets incorrectly partially expanded into
Group0 * CLASS_NAME_create (const PropertyList &list) { return new Group0 (list); } ...
But if I use one wrapper macro to call that one, it works. What is the rule for macro expansion here? Why does the first cls get expanded and the second one keeps the name?
A posible solution would be:
#include <iostream>
using namespace std;
#define CLASS_NUM 0
// String macros
#define XSTR(x) STR(x)
#define STR(x) #x
#define CONCAT(x,y) x##y
// XCONCAT will first process tokens before passing them to CONCAT
#define XCONCAT(x,y) CONCAT(x,y)
// This will generate Group0
#define CLASS_NAME XCONCAT(Group,CLASS_NUM)
// Then this will generate "Group0"
#define CLASS_STR XSTR(CLASS_NAME)
int main()
{
cout << "CLASS_NAME = " << CLASS_STR << endl;
return 0;
}
With this code the output is:
CLASS_NAME = Group0
The ## operator only works on tokens. So you need a helper macro.
Try this:
#include <ostream>
#include <iostream>
// the trouble
using namespace std;
// the trouble
// string troubles
#define STR(x) #x
#define XSTR(x) STR(x)
#define GROUP_NUM 0
#define CLASS_STR(g) XSTR(Group ## g)
#define CLASS_STR2(g) CLASS_STR(g)
int main()
{
cout << "CLASS_NAME = " << CLASS_STR2(GROUP_NUM) << endl;
return 0;
}
Use BOOST_PP_CAT for this:
#define CLASS_NAME BOOST_PP_CAT(Group,GROUP_NUM)
http://www.boost.org/doc/libs/1_54_0/libs/preprocessor/doc/ref/cat.html