I have the following set of macros (which I got from the first answer for How can I use the compile time constant __LINE__ in a string?) defined in an attempt to have a macro 'LOCATION_PREFIX' that I can use to "capture" the location of a line of code (will be passed to other functions that will perform logging).
#define STRINGIZE(f,l) STRINGIZE2(f) "(" STRINGIZE2(l)"):"
#define STRINGIZE2(x) #x
#define LOCATION_PREFIX STRINGIZE(__FILE__, __LINE__)
int main(){
printf("%s here\n", LOCATION_PREFIX);
printf("%s over here\n", LOCATION_PREFIX);
return 1;
}
Output:
"t.cpp"(8): here
"t.cpp"(9): over here
I want the output to be:
t.cpp(8): here
t.cpp(9): over here
Any help is greatly appreciated !
You don't need the first STRINGIZE2 invocation, as the file name is already a quoted string:
#define STRINGIZE(f,l) f "(" STRINGIZE2(l) "):"
#define STRINGIZE2(x) #x
#define LOCATION_PREFIX STRINGIZE(__FILE__, __LINE__)
int main(){
printf("%s here\n", LOCATION_PREFIX);
printf("%s over here\n", LOCATION_PREFIX);
return 1;
}
Related
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!
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
This is a standard C++ ASSERT macro defined in my code -
#ifndef DEBUG
#define ASSERT(n)
#else
#define ASSERT(n) \
if (!(n)){ \
printf("%s - Failed ", #n); \
printf("On %s ", __DATE__); \
printf("At %s ", __TIME__); \
printf("In File %s ", __FILE__); \
printf("At Line %d\n", __LINE__); \
exit(1);}
#endif
I want to ensure that my build always contains this code, by binding a unit test around it. The test should check that if #DEBUG preprocessor is not supplied (i.e. it is release mode), a conditional check applied in unit test should fail with ASSERT macro failing and containing the message given above.
Is there an established way to achieve this? I am using google test framework to achieve this, but unable to achieve the result. Test fails with standard assertion message, not the custom assertion I am trying it to fail with.
My code is as below -
TEST(VerifyNormalInitialization, VerifyAssert)
{
static int index = 0;
static int num = 4;
ASSERT(index == num);
EXPECT_FATAL_FAILURE(ASSERT(index == num),"Failed");
}
First the obvious the following raises only an error when DEBUG is defined.
ASSERT(index == num);
ASSERT(index != num);
For unit tests for both cases: production and development, you need to compile both ways.
You might effect that by your own #define/#undef DEBUG.
Good practice? I do not know; I was not aware that this was something worthwile testing. Maybe just a verification that ASSERTs are active during development. And that is something for an installation check.
Consider
EXPECT_FATAL_FAILURE(if (!(index == num)){ ... },"Failed");
Does that look like valid C++? It is not.
Consider writing a macro which passes along #n, __FILE__ etc to a proper function. If you insist on using a macro alone, then it needs to be a single expression and not a statement, something along the lines of:
#define STR2(x) #x
#define STR(x) STR2(x)
#define ASSERT(n) \
( \
fprintf(stderr, \
#n " - Failed on " __DATE__ " at " __TIME__ \
" in file " __FILE__ " at line " STR(__LINE__) \
), \
exit(EXIT_FAILURE) \
)
This is using compile-time string concatenation to prepare the whole string. Everything in this expression is string literals, and two string literals such as "hello" and "world" get concatenated by the pre-processor as "helloworld".
The "stringification" macros are just there to convert the integer __LINE__ into a string literal. Stringification - how does it work?
Note that the ), is the comma operator, which is used to allow two function calls in the same expression.
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).
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