base file name from __FILE__ - c++

I need the file name only where the __FILE__ and __FILEW__ macros return the whole path.
I defined the following:
#define __FILE_NAME_ONLY__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
I am using it as follows:
#define MY_TRACE( mask, format, ... ) \
GlobalTrace( mask, L"-[" __FILE_NAME_ONLY__ L":" format , __VA_ARGS__ )
I get the following error:
error C2064: term does not evaluate to a function taking 1 arguments
and when I try the following macros:
#define __WIDE(_String) L ## _String
#define _WIDE(_String) __WIDE(_String)
as follows
#define MY_TRACE( mask, format, ... ) \
GlobalTrace( mask, L"-[" _WIDE(__FILE_NAME_ONLY__) L":" format , __VA_ARGS__ )
I get : error C2146: syntax error : missing ')' before identifier 'L' when I actually try to use the MY_TRACE macro
what am I missing? Thanks

You're depending on string literal concatenation, except that all of the terms aren't string literals.
I assume you were previously doing it like so:
#define MY_TRACE( mask, format, ... ) \
GlobalTrace( mask, L"-[" __FILE__ L":" format , __VA_ARGS__ )
If __FILE__ and format expand to a string literal, the 4 strings get pasted together into one. "A" "B" "C" "D" is the same as "ABCD".
That doesn't happen when you replace with __FILE_NAME_ONLY__ because it expands to a function call, not a literal.

If you're using gcc this macro should help:
__BASE_FILE__
Here's a helpful list

Related

Is there any way to wrap a token in quotes with a #define? [duplicate]

I faced a problem - I need to use a macro value both as string and as integer.
#define RECORDS_PER_PAGE 10
/*... */
#define REQUEST_RECORDS \
"SELECT Fields FROM Table WHERE Conditions" \
" OFFSET %d * " #RECORDS_PER_PAGE \
" LIMIT " #RECORDS_PER_PAGE ";"
char result_buffer[RECORDS_PER_PAGE][MAX_RECORD_LEN];
/* ...and some more uses of RECORDS_PER_PAGE, elsewhere... */
This fails with a message about "stray #", and even if it worked, I guess I'd get the macro names stringified, not the values. Of course I can feed the values to the final method ( "LIMIT %d ", page*RECORDS_PER_PAGE ) but it's neither pretty nor efficient.
It's times like this when I wish the preprocessor didn't treat strings in a special way and would process their content just like normal code.
For now, I cludged it with #define RECORDS_PER_PAGE_TXT "10" but understandably, I'm not happy about it.
How to get it right?
The xstr macro defined below will stringify after doing macro-expansion.
#define xstr(a) str(a)
#define str(a) #a
#define RECORDS_PER_PAGE 10
#define REQUEST_RECORDS \
"SELECT Fields FROM Table WHERE Conditions" \
" OFFSET %d * " xstr(RECORDS_PER_PAGE) \
" LIMIT " xstr(RECORDS_PER_PAGE) ";"
#include <stdio.h>
#define RECORDS_PER_PAGE 10
#define TEXTIFY(A) #A
#define _REQUEST_RECORDS(OFFSET, LIMIT) \
"SELECT Fields FROM Table WHERE Conditions" \
" OFFSET %d * " TEXTIFY(OFFSET) \
" LIMIT " TEXTIFY(LIMIT) ";"
#define REQUEST_RECORDS _REQUEST_RECORDS(RECORDS_PER_PAGE, RECORDS_PER_PAGE)
int main() {
printf("%s\n", REQUEST_RECORDS);
return 0;
}
Outputs:
SELECT Fields FROM Table WHERE Conditions OFFSET %d * 10 LIMIT 10;
Note the indirection to _REQUEST_RECORDS to evaluate the arguments before stringifying them.
Try double escaping your quotes
#define RECORDS_PER_PAGE 10
#define MAX_RECORD_LEN 10
/*... */
#define DOUBLEESCAPE(a) #a
#define ESCAPEQUOTE(a) DOUBLEESCAPE(a)
#define REQUEST_RECORDS \
"SELECT Fields FROM Table WHERE Conditions" \
" OFFSET %d * " ESCAPEQUOTE(RECORDS_PER_PAGE) \
" LIMIT " ESCAPEQUOTE(RECORDS_PER_PAGE) ";"
char result_buffer[RECORDS_PER_PAGE][MAX_RECORD_LEN];
int main(){
char * a = REQUEST_RECORDS;
}
compiles for me. The token RECORDS_PER_PAGE will be expanded by the ESCAPEQUOTE macro call, which is then sent into DOUBLEESCAPE to be quoted.

std::to_string is not declared compile error in aix

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.

C/C++ macro expansion

I have the following code:
#define UNIT_BASIC_UNIT_DEF2 (name) UNIT_BASIC_ ## name
#define UNIT_UNIT_TYPE_DEF2 (basic_type, name) UNIT_ ## basic_type ## _ ## name
#define UNIT_BASIC_UNIT_CLASS_NAME2(name) CUnit ## name
#define UNIT_UNIT_TYPE_CLASS_NAME2(basic_type, name) CUnit ## basic_type ## _ ## name
#define UNIT_BASIC_UNIT_DEF (name) UNIT_BASIC_UNIT_DEF2(name)
#define UNIT_UNIT_TYPE_DEF (basic_type, name) UNIT_UNIT_TYPE_DEF2 (basic_type, name)
#define UNIT_BASIC_UNIT_CLASS_NAME(name) UNIT_BASIC_UNIT_CLASS_NAME2(name)
#define UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name) UNIT_UNIT_TYPE_CLASS_NAME2(basic_type, name)
#define UNIT_IMPLEMENT_UNIT_TYPE(basic_type, name) \
CUnitAbstract& UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name)::dup(){\
UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name) * n = new UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name)(this->value);\
return *n;\
}\
CUnitAbstract& UNIT_UNIT_TYPE_CLASS_NAME(basic_type, name) ::operator+(CUnitAbstract& value){\
DYNAMIC_ASSERT(dynamic_cast< UNIT_BASIC_UNIT_CLASS_NAME(basic_type) *>(&value) != NULL);\
CUnitAbstract * tmp = &this->dup();\
*tmp = this->value + conversionTable[UNIT_BASIC_UNIT_DEF(basic_type)][UNIT_UNIT_TYPE_DEF(basic_type, name)] * value.getInBasicUnit();return *tmp;\
}
When I'm calling the macro with
UNIT_IMPLEMENT_UNIT_TYPE(DISTANCE, METER)
I get compilation errors:
error: 'basic_type' was not declared in this scope
error: 'name' was not declared in this scope
error: expected ']' before 'UNIT_basic_type_name'
error: expected ';' before 'UNIT_basic_type_name'
meaning that the macro wasn't expanded as I wanted it to in the last line inside the brackets.
What did I do wrong?
#define UNIT_BASIC_UNIT_DEF2 (name) UNIT_BASIC_ ## name
#define UNIT_UNIT_TYPE_DEF2 (basic_type, name) UNIT_ ## basic_type ## _ ## name
...
#define UNIT_BASIC_UNIT_DEF (name) UNIT_BASIC_UNIT_DEF2(name)
#define UNIT_UNIT_TYPE_DEF (basic_type, name) UNIT_UNIT_TYPE_DEF2 (basic_type, name)
Remove the spaces between the macro name and the argument list. These should be:
#define UNIT_BASIC_UNIT_DEF2(name) ...
// ^^^
// no space here!
When there's a space like this:
#define FOO (params) replacement
that defines an object-like macro, where the symbol gets directly replaced by the replacement list, with no parameter substitution. So an invocation like this:
FOO(bar)
gets expanded to this:
(params) replacement
By removing the space, you get a function-like macro as intended:
#define FOO(params) replacement
and FOO(bar) gets correctly expanded to replacement.

Concatenating #define in C++

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.

Macro String with variable

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 #