Macro long string concernation - c++

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;
}

Related

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

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.

Macros in system calls

In c++, is it possible and safe to use macros in system calls? Take the following code for example:
#define WINX 54
#define WINY 30
int main()
{
system("mode con lines=WINY cols=WINX");
...
Would that work and be safe to use in code? Or would I have to manually construct a string?
A macro will not expand inside a string literal. Instead, you can use another macro to expand a macro into a string literal, and use string literal concatenation to create the desired string:
#define STR2(x) STR(x)
#define STR(x) #x
const char *cmd = "mode con lines=" STR2(WINY) " cols=" STR2(WINX);
system(cmd);
STR2 expands the provided argument (e.g. WINY) into what it is defined to be and then passes it to STR. STR just uses the stringifying macro operator, and its result is a string literal. Adjacent string literals are concatenated into a single string by the compiler before the code is tokenized and compiled into object code.
If the macros are something more complex than simple numbers, then you need to manually construct a string. In C++, the easiest way is to use ostringstream (from <sstream>):
std::ostringstream oss;
oss << "mode con lines=" << WINY << " cols=" << WINX;
system(oss.str().c_str());
Macros certainly don't expand in strings. So, this
system("mode con lines=WINY cols=WINX");
won't expand into
system("mode con lines=30 cols=54");
If you don't need the actual decimal value of WINX and WINY, you can concatenate static strings and save resources during execution time:
#define WINX "54"
#define WINY "30"
int main()
{
system("mode con lines=" WINY " cols=" WINX);
You'll have to manually construct a string.
For example:
char command[100];
int result;
sprintf(command, "mode con lines=%d cols=%d", WINY, WINX);
result = system(command);
Don't forget the required include directives:
#include <stdio.h>
#include <stdlib.h>
Consult your system's documentation for the meaning of the value returned by system.
Make sure the command array is big enough to hold the full command -- or, probably better, use std::string instead. jxh's answer shows how to do this.

Understanding a C++ Macro that uses #

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.

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.