I don't know how to define a macro string with variable, like this:
#define str(x) "file x.txt", that mean I desire that str(1) refers to "file 1.txt".
However, in the case, str(1) or any number refers to "file x.txt", because x is an character.
Is there any way to solve this?
Concatenate the strings:
#define STR(x) "file " #x ".txt"
This makes use of a lexical feature of the two languages: adjacent string literals are concatenated; see both C++11 2.2/6 and C11 5.1.1.2/6:
Adjacent string literal tokens are concatenated.
#define str(x) ("file " #x ".txt")
using the stringification operator #
Related
My question is the inverse of this question.
I want to write a macro that will accept an integer and a string literal as it's arguments, like so:
#define STRING_MAP_ENTRY(value, name) \
{value, std::to_string(val) + " - " + name}
STRING_MAP_ENTRY(0, "ENTRY_1")
The macro should turn the above call into {0, "0 - ENTRY_1"}
Is there a way to do this? My current attempt is this:
#define STRING_MAP_ENTRY(val, name) \
{ val, std::to_string(val) + "(" + name + ")" }
Something like this could work:
#define STRING_MAP_ENTRY(value, name) \
{value, #value " - " #name}
STRING_MAP_ENTRY(0, ENTRY_1)
the # before a token will stringify it. As for combining them, adjacent string literals will be combined into a single string.
Why do you want to use macro?
It's not good.
Use this:
auto STRING_MAP_ENTRY(int value_,string name_){
struct{int value;string name;} pair_{value_,to_string(value_)+string(" - ")+name_};
return pair_;
}
And use this to check if it works:
auto aa= STRING_MAP_ENTRY(0,string("ENTRY_1"));
cout<<aa.value<<','<<aa.name<<endl; // 0,0 - ENTRY_1
Remember:
Always use FUNCTION not MACRO!!
I am compiling my code in AIX env.. it givs me error "std::to_string" is not declared
successfully compiled same code in Windows.
define LOG_MSG(message) CLogManager::LogMessage(CLogManager::CurrentDateTime() + " - " + std::string(__FILE__) + "[" + std::to_string(static_cast<_ULonglong>(__LINE__)) + "] : " + std::string(message) + "\n")
This is the macro and i am using this as
LOG_MSG(" ** BEGIN StorePasswordFromFile()");
This macro is for logging purpose
I'm not sure how much support the latest xlC 14.1 (or whatever version you're using) has for std::to_string().
If the support is incomplete, C has a hideous double macro method (a) of turning __LINE__ into a C-string so that you can just use std::string, the same as you have for the __FILE__ and message items, and it appears the C++ pre-processor has stayed faithful to its hideous roots :-)
The code:
#include <stdio.h>
#define STR1(x) # x
#define STR2(x) STR1(x)
int main(void) {
char x[] = __FILE__;
char y[] = STR2(__LINE__);
printf("file = %s, line = %s\n",x,y);
return 0;
}
outputs:
file = qq.c, line = 6
showing that the __LINE__ has been successfully morphed into a C-string value.
You should be able to use a similar method in your macro:
#define STR1(x) # x
#define STR2(x) STR1(x)
#define LOG_MSG(message) CLogManager::LogMessage( \
CLogManager::CurrentDateTime() + " - " + \
std::string(__FILE__) + "[" + \
std::string(STR2(__LINE__)) + "] : " + \
std::string(message) + "\n")
int main() {
LOG_MSG ("My hovercraft is full of eels");
return 0;
}
Pre-processing that with g++ -E qq.cpp gives you:
CLogManager::LogMessage( CLogManager::CurrentDateTime() + " - " + std::string("qq.cpp") + "[" + std::string("10") + "] : " + std::string("My hovercraft is full of eels") + "\n");
(showing relevant line only) which seems to match what you want.
As a side note however, since you seem to be okay adding C-strings like "[" without needing to construct strings explicitly, I'm not sure that you need the std::string() calls at all for those. You still need the C macro hack to turn the integer into a C-string but, once that's been done, you should just be able to use that as-is.
Changing the final macro to:
#define LOG_MSG(message) CLogManager::LogMessage( \
CLogManager::CurrentDateTime() + " - " + \
__FILE__ + "[" + \
STR2(__LINE__) + "] : " + \
message + "\n")
will give you:
CLogManager::LogMessage( CLogManager::CurrentDateTime() + " - " + "qq.cpp" + "[" + "10" + "] : " + "My hovercraft is full of eels" + "\n");
Whether that's a good idea, I'll leave to the wider community but it at least gets around your immediate problem. I'd probably place the whole lot inside an #if/#else/#endif so that C++11 compilers that know about std::to_string() can use the more accepted approach.
(a) If you're interested in why this works, I'll explain below.
The # and ## macro operators actually take precedence over the recursive nature of macro replacement, as per C11 6.10.3.4 /1:
After all parameters in the replacement list have been substituted and # and ##
processing has taken place, all placemarker preprocessing tokens are removed. The
resulting preprocessing token sequence is then rescanned, along with all subsequent
preprocessing tokens of the source file, for more macro names to replace.
That means that the code:
#define STR(x) # x
STR(__LINE__)
will actually result in "__LINE__" because the # happens first and, once that's happened, the __LINE__ within the string literal is not subject to further replacement. By doing the two-step process:
#define STR1(x) # x
#define STR2(x) STR1(x)
STR2(__LINE__)
the first level of replacement turns STR2(__LINE__) into STR1(3) because __LINE__ on its own is subject to expansion.
Then the second level turns STR1(3), via # 3, into "3".
Perhaps the following may help:
#define STR1(x) # x
#define STR2a(x) STRn(x)
#define STR2b(x) STR1(x)
STR1(__LINE__)
STR2a(__LINE__)
STR2b(__LINE__)
The output of that, annotated, is:
"__LINE__" - stringise, no further processing of __LINE__ inside literal.
STRn(6) - shows first stage of replacement, line number replacement.
"7" - shows full process.
#include <iostream>
int main() {
std::string s = "?????";
std::cout << s << std::flush;
}
What should I write in the s variable to output \"\"' (these 5 characters?)
Escape them like this (prepend \ to each of the special characters):
"\\\"\\\"'"
The other option is C++11 raw string literal:
R"(\"\"')"
Since C++11, you can put whatever characters you like in a raw string literal:
R"(\"\"')"
Historically, you would have to escape \ and " with \ in a normal string literal:
"\\\"\\\"'"
You need to escape the \ and " characters with \
std::string s = "\\\"\\\"'";
In C++11, you can also use a raw string literal
R"(\"\"')"
I have something like:
#define BASE_FOLDER = "Resources"
#define PREFERENCE_FILE_NAME = "AppPreferences.txt"
#define SPLASH_FILE_NAME = "Splash.png"
#define PREFERENCE_PATH = ".\\" + BASE_FOLDER + "\\" + PREFERENCE_FILE_NAME
#define SPLASH_PATH = ".\\" + BASE_FOLDER + "\\" + SPLASH_FILE_NAME
and the compiler is throwing errors where PREFERENCE_PATH is used.
expecting primary expression before = token.
These all worked when I was doing
#define PREFERENCE_PATH = ".\\Resources\\AppPreferences.txt"
#define SPLASH_PATH = ".\\Resources\\Splash.png"
What am I doing wrong?
Get rid of the equal signs. Preprocessor definitions don't use equal signs.
Then get rid of the pluses. String literals are concatenated when you put them side by side without a plus in between. Emphasis on literals because this is a compile-time feature that only works with double-quoted literals, as in "foo" "bar" → "foobar". It doesn't work with variables.
#define BASE_FOLDER "Resources"
#define PREFERENCE_FILE_NAME "AppPreferences.txt"
#define SPLASH_FILE_NAME "Splash.png"
#define PREFERENCE_PATH ".\\" BASE_FOLDER "\\" PREFERENCE_FILE_NAME
#define SPLASH_PATH ".\\" BASE_FOLDER "\\" SPLASH_FILE_NAME
You can't concatenate strings (char* that is) in C++ like that...there is no + operator for them.
I can't realize how could it be possible to print a string this way without any complaint by the compiler:
std::cout << "Hello " "World!";
In fact, the above line works exactly like:
std::cout << "Hello " << "World!";
Is there an explanation for this behaviour?
Adjacent literal tokens are concatenated automatically, it's part of the standard.
2.1 Phases of translation [lex.phases]
6) Adjacent ordinary string literal tokens are concatenated. Adjacent wide string literal tokens are concatenated.
(C++03)
In C++, literals tokens can be concatenated thusly:
const char* thingy = "Hello" "World";
"Hello" and "World" are each a literal token.
This is normal behavior of the strings. In the first line specified strings are concatenated by compiler automatically. As sample you can specify also multiline to avoid very long line.
const char *strLine = "line 1 "
"line 1 "
"line 2 ";
And it will work OK. The second line is cleared, specified another line for output.