I have a C++ macro with a syntax that I have never seen before:
#define ASSERT(a) \
if (! (a)) \
{ \
std::string c; \
c += " test(" #a ")";
}
Couold you please explain me the use of # in here?
I wanted to put the macro in a static function but before I would like to fully understand what it does.
Thanks
The use of # in a macro means that the macro argument will be wrapped in quotes "":
#define FOOBAR(x) #x
int main (int argc, char *argv[])
{
std::cout << FOOBAR(hello world what's up?) << std::endl;
}
output
hello world what's up?
Another example
In the below we display the contents of foo.cpp, and then what the file will look like after the pre-processor has run:
:/tmp% cat foo.cpp
#define STR(X) #X
STR (hello world);
...
:/tmp% g++ -E foo.cpp # only run the preprocessor
# 1 "foo.cpp"
# 1 "<command-line>"
# 1 "foo.cpp"
"hello world";
Where can I read more?
Check out the following link to a entry in the cpp (C Pre Processor) documentation:
Stringification - The C Preprocessor
Within a macro the # "stringifies" the variable name. By "stringify" I mean, the variable name is transformed into a string literal.
For example when you have the following macro:
#define PRINT_VARIABLE_NAME(var) printf(#var);
And use it like that:
int i;
PRINT_VARIABLE_NAME(i);
It would print "i".
In your case the string would get concatenated with "test".
#a is a string containing the literal a. See Stringfication for more.
Related
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).
In my application I want to add the version ID as a macro and use it in multiple parts of the application. As explained in this question I can easily generate a string with this:
#define APP_VER "1.0"
#define APP_CAPTION "Stackoverflow example app v." ## APP_VER
My problem is now, that in some parts, I need to have the caption as an unicode string.
I tried the following:
MessageBoxW(0,_T(APP_CAPTION),L"Minimal Counterexample",0);
But it gives the error "can't concernate wide 'Stackoverflow example app v.' with narrow '1.0'"
I also tried
#define WIDE_CAPTION L ## APP_CAPTION
But that just gives "LAPP_CAPTION" is not defined.
I know that I can convert the string at runtime to unicode, but that is rather messy. Can someone provide a Macro-level solution for my problem?
You just want:
#define APP_CAPTION "Stackoverflow example app v." APP_VER
Since APP_VER is already a string.
String concatenation happens for free, for example:
const char *str = "hello " "world"
Complete compilable example:
#include <iostream>
#define APP_VER "1.0"
#define APP_CAPTION "Stackoverflow example app v." APP_VER
int main() {
std::cout << APP_CAPTION << "\n";
return 0;
}
#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.