How to call macro that uses token pasting? - c++

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

Related

Looping with macros

I need to do a loop where I turn this simple example of reflection:
std::string mystring[3] = {{"mystring[0]"},{"mystring[1]"},{"mystring[2]"}};
into a more managable form for longer arrays. The solution sounds like I should either use macros with a loop, or recursion. However, macros don't support loops or recursion!
How do I create a macro to handle this for me arbitrarily?
#define NAME_OBJ(type, name, size)
Try using Boost. If it fails, try using more Boost.
#include <boost/preprocessor/repeat.hpp>
#include <boost/preprocessor/comma_if.hpp>
#include <boost/preprocessor/stringize.hpp>
#define DETAIL_NAME_OBJ_ELEM(z, n, name) \
BOOST_PP_COMMA_IF(n) { BOOST_PP_STRINGIZE(name) "[" BOOST_PP_STRINGIZE(n) "]" }
#define NAME_OBJ(type, name, size) \
type name[size] = { BOOST_PP_REPEAT(size, DETAIL_NAME_OBJ_ELEM, name) }
Then this:
NAME_OBJ(std::string, mystring, 3);
... expands to this:
std::string mystring[3] = {
{ "mystring" "[" "0" "]" },
{ "mystring" "[" "1" "]" },
{ "mystring" "[" "2" "]" }
};
... in which the adjacent string literals are then automatically merged before compilation.
See it live on Coliru
As you stated, macros in C++ do not support loops or recursion, such that you would have to duplicate lines of code.
A common way of solving such topics is to write a program - let's say myGenerator, which contains a "normal" C++-loop and which's output is a C++ source file (.cpp or .h). Integrate then a call to myGenerartor in a build step before building the rest of your program.
Based on a great answer to handling macros here
https://stackoverflow.com/a/12540675/1723954
I modified/simplified the solution for this specific case:
#define NAME_OBJ(type, name, size) \
type name[size] = { INIT_ELEMENT_ ## size(name) }
#define INIT_ELEMENT_1(name) { #name "[0]" }
#define INIT_ELEMENT_2(name) INIT_ELEMENT_1(name), { #name "[1]" }
#define INIT_ELEMENT_3(name) INIT_ELEMENT_2(name), { #name "[2]" }
...
The solution does not allow for very-very-very large arrays, only as large as you are willing to code. I did 128 and that's fine for all of the cases in my project.

Why is this macro generating a syntax error?

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__)

How to print C-preprocessor variables like __LINE__ with mexErrMsgTxt() In Matlab MEX

For debugging Matlab-MEX, which can be quite a hassle, it would be nice to have better assertion capabilities. Following this question about mex-assertions, it is possible to define a preprocessor makro, that throws an error to Matlab and prints a string (can mostly replace mxAssert, which unfortunately crashes Matlab2011b).
#define myassert( isOK,astr ) ( (isOK) ? (void)0 : (void) mexErrMsgTxt(astr) )
It would be much nicer to print the file, line number and caller function, from where following example assertion myassert(A=B,"A not B") is raised! This answer to the initial question states that they are the preprocessor variables:
__LINE__,__PRETTY_FUNCTION__, __FILE__
How can we print these preprocessor variables with mexErrMsgTxt?
The problem is, that mexErrMsgTxt() takes a char* argument and not multiple inputs like for example printf(const char *format, ...).
My thinking goes only so far at the moment:
It's not possible to build a function, because the preprocessor variables will have the values (e.g. line number) from the function.
It was not possible for me to write a working multiline preprocessor makro that creates a char from the passed string astr and passes it to mexErrMsgTxt(). Maybe a solution is along these lines.
A hybrid solution with a char creating preprocessor makro and a function that passes it to mexErrMsgTxt() doesn't feel like good coding practice.
It would be really nice to make the specified error string optional.
Concatenating preprocessor tokens works as long as you only use __FILE__, __LINE__ and a string literal as message. Then you can write something like
#define STRINGIZE_I(x) #x
#define STRINGIZE(x) STRINGIZE_I(x)
#define myassert(isOK, astr) ( (isOK) ? (void)0 : (void) mexErrMsgTxt(__FILE__ ":" STRINGIZE(__LINE__) ": " astr) )
Unfortunately, __PRETTY_FUNCTION__ is not a string literal even for those compilers who support it. If you want to use it (or less fixed error messages), you'll have to assemble the string dynamically, which means something along the lines of
#define myassert(isOK, astr) \
do { \
if(!(isOk)) { \
std::ostringstream fmt; \
fmt << "In " << __PRETTY_FUNCTION__ << ", " \
<< __FILE__ << ":" << __LINE__ << ": " << (astr); \
(void) mexErrMsgTxt(fmt.str().c_str()); \
} \
} while(false)
For C, do the same with snprintf. (Or asprintf. It avoids problems with fixed buffer lengths and long error messages, and it is about as portable as __PRETTY_FUNCTION__). Either way, roughly like
#define myassert(isOK, astr) \
do { \
if(!(isOk)) { \
char buf[ENOUGH_SPACE]; \
snprintf(buf, ENOUGH_SPACE, "In %s, %s:%d: %s", \
__PRETTY_FUNCTION__, __FILE__, __LINE__, (astr)); \
buf[ENOUGH_SPACE - 1] = '\0'; \
(void) mexErrMsgTxt(buf); \
} \
} while(0)
...where ENOUGH_SPACE would have to be defined appropriately (in the snprintf case).

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

How to Replace only Part of the Variable using #define

#define C_TX_ TX_
#define C_RX_ RX_
enum Test
{
C_TX_MAC = 0x0100, // Pre-Processor should replace C_TX_ to TX_
C_RX_MAC = 0x0101 // But Not Working.
};
int main(int argc, char *argv[])
{
cout << TX_MAC; // HOW TO PRINT ?
cout << RX_MAC; // HOW TO PRINT ?
return true;
}
The pre-processor only operates on strings that are entire tokens. There would be chaos otherwise.
Try:
#define C_TX_MAC TX_MAC
#define C_RX_MAC RX_MAC
You cannot split a token with the pre-processor. You need to
#define C_RX_MAC RX_MAC
#define C_TX_MAC TX_MAC
(Of course there's ugly solutions such as adding a pre-pre-processing step:
sed s/C_ADDR_// x.cpp | g++ -x c++ -
But sed doesn't know about the context. It will replace strings e.g. cout << "And C_ADDR_RX = " with cout << "And RX = ".)
As stated in the other answers the pre-processor uses the whitespace to work out where the token is defined, and cannot replace it 'part way through". Perhaps you could try a "Find/Replace In Files" to rename the variables in your source code directly. Visual Studio's Find and Replace function can be used to replace any occurences in any folders/subfolders, or if you don't run with the Microsoft there's some other programs like NotePad++ that offer the same functionality. Both also support Regular Expressions for better targeted find/replace queries
The preprocessor replaces tokens, and C_TX_MAC is a full token.
However, you can achieve this fairly easily with some macro concatenation:
#include <iostream>
#define foo(x) C_ ## x
enum Test
{
C_TX_MAC = 0x0100, // Pre-Processor should replace C_TX_ to TX_
C_RX_MAC = 0x0101 // But Not Working.
};
int main()
{
std::cout << foo(TX_MAC) << ' ' << foo(RX_MAC) << '\n';
}
(live demo)
Easy. No need for sed, and no need for find-and-replace in your text editor.