Convert C++ log source snippet to Windows Phone C++/CX - c++

I just started developing for Windows Phone and I'm stuck with one piece of exisiting code I need to maintain. It's a macro from a logging lib that is used in many places of existing code.
This is the macro:
#define LOG_FORMAT_FUNCTION(fmtarg, firstvararg) __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
And this is a method definition that fails to use the above macro with error "{ expected" (In German "Error: Es wurde ein '{' erwartet."):
void LogTrace_s(const char* category, const char* format, ...) LOG_FORMAT_FUNCTION(2, 3);
Can you help me get rid of the error? I'd also like to know what actually the macro does exactly.
Edit: After rading this here I now understand that this macro is good for error checking formatted strings. Now that I know, I need it even more. But I still have no clue how to translate this to MS C++.

Yes you CAN just omit it. Use
#if _MSVC_VER
#define LOG_FORMAT_FUNCTION(fmtarg, firstvararg)
#endif
It is annotating the function with extra information to help gcc give you better warnings. It does not change the behavior of the code in any way.

Related

How to inject environment variables into CPP file using Visual Code and Platform IO?

Just starting with this coming from a JS background.
I am looking into IoT development and wanted to set up my own repo without uploading the SSID and password of my personal WiFi.
Platform IO offers this platformio.ini as I understand to set build_flags.
build_flags =
-D SSID="MySSID"
I don't know how to access them from my CPP file though. I want to inject the value from the build flag SSID into my *.cpp file.
#define SSID
void loop()
{
Serial.println(SSID);
}
The above doesn't write anything to the serial monitor.
What am I doing wrong? The code does compile.
I know it's been two years, and you've probably moved on from this question. However, for anyone else - like myself - who happens across this from a Google search, here is the answer as I've found it:
According to PlatformIO's Dynamic Variables page, you correctly define the build variable so that it exists to C++ (as a macro); i.e., -DSSID="MySSID". What you missed, however, is that the values need to be quoted (and potentially escaped): -DSSID='"MySSID"' so that when you access the macro in C++ it is a const char * string and not an unknown symbol.
See the Warning at the bottom of the page, and note the quotes around the string:
Be careful with special characters in system environment variables on Unix systems, especially when they are used as the value for preprocessor directives. Symbols like $, &, ~, etc must be explicitly escaped, for example:
export WIFI_PASS='\"my\~p\&a\\\$\$\$\$word\"'
It wasn't initially obvious to me either, but it makes sense because the preprocessor will replace SSID with whatever you've defined and makes no assumptions about it or its type at all.
As #Azeem mentioned, you're redefining the SSID to an empty value. Using preprocessor like this, you must first check if the value exist and if not, assign it a default value.
Here is a simple C++ example:
#include <iostream>
#ifndef SSID
#define SSID "(SSID not defined)"
#endif
int main()
{
std::cout << "SSID value: " << SSID << std::endl;
return 0;
}
You can compile and run the code with:
g++ main.cpp -o main && ./main
As you see it prints (SSID not defined).
Now, compiling and running with the following:
g++ main.cpp -o main -DSSID='"Hello, World!"' && ./main
will output: SSID value: Hello, World!
If you want to learn more about preprocessor directives, cplusplus.com has very nice tutorial
Also, don't forget to start your Serial in void setup().

strncasecmp and strcasecmp has not been declared

I'm trying to compile Assimp with MinGW in Code::Blocks, but I get the following errors.
\assimp-3.3.1\assimp-3.3.1\code\StringComparison.h||In function 'int Assimp::ASSIMP_stricmp(const char*, const char*)':|
\assimp-3.3.1\assimp-3.3.1\code\StringComparison.h|144|error: '::strcasecmp' has not been declared|
\assimp-3.3.1\assimp-3.3.1\code\StringComparison.h||In function 'int Assimp::ASSIMP_strincmp(const char*, const char*, unsigned int)':|
\assimp-3.3.1\assimp-3.3.1\code\StringComparison.h|193|error: '::strncasecmp' has not been declared|
While searching I've found out that the two functions in question (strcasecmp and strncasecmp) are in fact declared in string.h which is included in the header of StringComparison.h. I've also managed to get strings.h, the file which they originally belong to, but including that didn't solved the issue either.
While searching this site I've found out that I'm not the only one struggling with this issue. Another solution I've found suggested to use define statements, because the functions might have a slightly different name, but that didn't helped either.
I just encountered this exact same problem, and this question came up during a Google search for the solution, so I'll document my dodgy solution here:
In the end I got it going just by making multiple small edits to the Assimp source code. Solving the string problem isn't enough to get it to work because it just fails later in the build. I'll list the edits I made below. I recommend making them one at a time and then rebuilding, just in case for whatever reason with your setup some of them aren't required. Note that you can't do model exporting with this solution because of the last edit (to Exporter.cpp) if you really need that you'll have to figure out another way to fix the link errors.
It's not a clean solution and it will probably be superceded by a future version of Assimp, at which point I will just delete it. This is for assimp-3.3.1, built with MinGW:
In StringComparison.h, edit the ASSIMP_stricmp function, commenting out everything except the else clause of the #ifdef:
/*#if (defined _MSC_VER)
return ::_stricmp(s1,s2);
#elif defined( __GNUC__ )
return ::strcasecmp(s1,s2);
#else*/
char c1, c2;
do {
c1 = tolower(*s1++);
c2 = tolower(*s2++);
}
while ( c1 && (c1 == c2) );
return c1 - c2;
//#endif
Do a similar thing in ASSIMP_strincmp.
Next, it throws up an error about ::_fullpath in DefaultIOSystem.cpp. My "fix" for this was just to use comment out everything other the fallback option in this function:
ai_assert(in && _out);
// char* ret;
//#if defined( _MSC_VER ) || defined( __MINGW32__ )
// ret = ::_fullpath( _out, in, PATHLIMIT );
//#else
// use realpath
// ret = realpath(in, _out);
//#endif
// if(!ret) {
// preserve the input path, maybe someone else is able to fix
// the path before it is accessed (e.g. our file system filter)
// DefaultLogger::get()->warn("Invalid path: "+std::string(in));
strcpy(_out,in);
// }
It also complains about snprintf being undefined. Edit StringUtils.h to change the following #define to add an underscore before snprintf:
# define ai_snprintf _snprintf
There's also an error about ::atof not being defined. You can fix this by adding
#include <cstdlib>
to StringUtils.h
This should get it building but there will be a link error in Exporter.cpp (this might be due to my specific CMake setttings because I disabled almost all model formats). I fixed it by commenting out the definition of gExporters and replacing it with this:
Exporter::ExportFormatEntry* gExporters = 0;
After this it built and ran fine. The library files are placed in the code folder. Place libassimp.dll.a in your lib build path and libassimp.dll in the path of your executable.
Of course, you can also get it going by using VisualStudio instead (I didn't because I couldn't be bothered installing it) or by building on Linux (I did this previously and it built fine first go, but I needed to do a Windows port).
I had some problems too but hopefully I was able to solve them. I know this is probably too late to help in particular but I hope someone on the Internet will find this useful. I compile using Code::Blocks 16.01 using gcc 5.3.0.
::strncasecmp not declared in this scope:
You have to include and remove the "::"
::_fullpath not declared in this scope:
I never had to perform the operation of finding a full path, so this one is the one I am the least sure of. But anyway, since I couldn't simply remove everything, I had to find the alternative. That is, using "GetFullPathName".
So, as suggested by MSDN, I included , , , .
I also replace the line :
ret = _fullpath( _out, in, PATHLIMIT );
by
ret = (char*)GetFullPathName(in, PATHLIMIT, _out, NULL);
Should work fine, full path is obtained and error checking is kept too.
vsnprintf not declared in this scope
Just add an underscore _ in front of the function name.
to_string is not a member of std::
I would have that this is the usual bug from using MinGW, but actually, Assimp contains a built-in alternative to std::to_string. You just have to remove the std:: part and it should roll.
Make sure to include in the files in which just removing std:: doesn't work.
test\CMakeFiles\gtest.dir\build.make|109|recipe for target 'test/gtest/src/gtest-stamp/gtest-build' failed| ?
It doesn't matter, you already have your working .dll in the "code" folder ;)
I was using Cygwin and encounter the same error, using strncmp and strcmp worked, guessing it is something to do with the libraries (ANSI C++) currently implemented for Cygwin or being used by your project. Not sure though, just wanted it to work for the moment...

How do I use _DEBUG_ERROR in my own code?

Inside the <vector> header, there is code like this:
_DEBUG_ERROR("vector iterator not dereferencable");
_SCL_SECURE_OUT_OF_RANGE;
Which halts the program with a message and gives the programmer a chance to debug the code.
For a little toy project, I want to use _DEBUG_ERROR myself. It is defined in <xutility>.
However, when I include <xutility> and try to use _DEBUG_ERROR, I get the following error:
error C3861: "_Debug_message": identifier not found.
But _Debug_message is defined inside <xutility>, in line 28! Why does the compiler complain?
Also, is there another (maybe even somewhat portable?) way to halt the program for debugging?
Not 100% certain but I'm fairly sure it's actually std::_Debug_message. And PlasmaHH is right: assert() is the normal solution. You can write assert(!"message") to get a custom message. (Note the !)
You can use ASSERT or _ASSERT macro for assert-and-debug. Or, you can craft your own assert-macro. Use the definition of _ASSERT (taken from crtdbg.h):
#define _ASSERT_EXPR(expr, msg) \
(void) ((!!(expr)) || \
(1 != _CrtDbgReportW(_CRT_ASSERT, _CRT_WIDE(__FILE__), __LINE__, NULL, L"%s", msg)) || \
(_CrtDbgBreak(), 0))
The important function here is _CrtDbgReportW, which will display the assertion dialog-box having three standard buttons (Abort, Retry and Ignore). Depending on return value you can then call other functions. In the macro given above, function _CrtDbgBreak is called when user hits 'Retry' button (which causes function to return 1, see MSDN).
You may write to a log file, display to debug output window (using OutputDebugString), or do things you may like.

Strange enum name clash

I am compiling a project that uses both ffmpeg and Ogre.
Now on Windows, everything works fine.
But when I want to compile a file with the following line of code:
Ogre::PixelFormat format = Ogre::PF_BYTE_RGBA;
The compiler gives the following error:
error: ‘AVPixelFormat’ is not a member of ‘Ogre’
Which is strange in many ways, as I have not only specified the Ogre namespace with ::, but also there is no AVPixelFormat in Ogre. How does gcc confuse "PixelFormat" with "AVPixelFormat"?
And how can I get rid of that?
I'd love to use int here instead of an enum, but another Ogre function requires format to be in Ogre::PixelFormat.
Preprocess it first using gcc -E, then grep through the file looking for AVPixelFormat or PixelFormat. I suspect you have a #define or a typedef floating around, you just need to find where this happens, and a precompiled source file is the place this will become apparent.
The problem is in avutil/pixfmt.h:
#define PixelFormat AVPixelFormat
This prevents users from using the word "PixelFormat" anywhere in their own code, even if in namespaces.
This is there as a compatibility hack for older software still using the old identifiers.
The solution is quite simple in case you can edit the code. Just add to the C++ code a
#define FF_API_PIX_FMT 0
before including the ffmpeg headers.
This disables the if in the pixfmt.h header:
#if FF_API_PIX_FMT
#define PixelFormat AVPixelFormat
...
Source: https://trac.ffmpeg.org/ticket/4216
P.S. I know the question is old, but somehow I feel that there is no solution and I needed a solution, so I added it.

Is there a TRACE statement for basic win32 C++?

In MFC C++ (Visual Studio 6) I am used to using the TRACE macro for debugging. Is there an equivalent statement for plain win32?
_RPTn works great, though not quite as convenient. Here is some code that recreates the MFC TRACE statement as a function allowing variable number of arguments. Also adds TraceEx macro which prepends source file and line number so you can click back to the location of the statement.
Update: The original code on CodeGuru wouldn't compile for me in Release mode so I changed the way that TRACE statements are removed for Release mode. Here is my full source that I put into Trace.h. Thanks to Thomas Rizos for the original:
// TRACE macro for win32
#ifndef __TRACE_H__850CE873
#define __TRACE_H__850CE873
#include <crtdbg.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#ifdef _DEBUG
#define TRACEMAXSTRING 1024
char szBuffer[TRACEMAXSTRING];
inline void TRACE(const char* format,...)
{
va_list args;
va_start(args,format);
int nBuf;
nBuf = _vsnprintf(szBuffer,
TRACEMAXSTRING,
format,
args);
va_end(args);
_RPT0(_CRT_WARN,szBuffer);
}
#define TRACEF _snprintf(szBuffer,TRACEMAXSTRING,"%s(%d): ", \
&strrchr(__FILE__,'\\')[1],__LINE__); \
_RPT0(_CRT_WARN,szBuffer); \
TRACE
#else
// Remove for release mode
#define TRACE ((void)0)
#define TRACEF ((void)0)
#endif
#endif // __TRACE_H__850CE873
From the msdn docs, Macros for Reporting:
You can use the _RPTn, and _RPTFn macros, defined in CRTDBG.H, to replace the use of printf statements for debugging. These macros automatically disappear in your release build when _DEBUG is not defined, so there is no need to enclose them in #ifdefs.
There is also OutputDebugString. However that will not be removed when compiling release.
Trace macros that provide messages with source code link, run-time callstack information, and function prototype information with parameter values:
Extended Trace: Trace macros for Win32
I just use something like this (from memory, not tested at all...)
#define TRACE(msg) {\
std::ostringstream ss; \
ss << msg << "\n"; \
OutputDebugString(msg.str()); \
}
And then I can write things like :-
TRACE("MyClass::MyFunction returned " << value << " with data=" << some.data);
You can wrap that in some #ifdefs to remove it in release builds easily enough.
I found that using the _RPT() macro will also work with a C source file in Visual Studio 2005. This article Debugging with Visual Studio 2005/2008: Logging and Tracing provides an overview of TRACE, _RPT, and other logging type macros.
I generate a line for a log file called the ASSRTLOG which contains logs and when writing the log to the file, I also do the following source code line:
_RPT1(_CRT_WARN, "ASSRTLOG: %s", szLog1);
This line puts the same log that is going into the log file into the output window of the Visual Studio 2005 IDE.
You might be interested in the mechanics behind the approach we are using for logging. We have a function PifLogAbort() which accepts a series of arguments that are then used to generate a log. These arguments include the name of the file where the log is being generated along with the line number. The macro looks like this:
#define NHPOS_ASSERT_TEXT(x, txt) if (!(x)) { PifLogAbort( (UCHAR *) #x , (UCHAR *) __FILE__ , (UCHAR *) txt , __LINE__ );}
and the function prototype for PifLogAbort() look like this:
PifLogNoAbort(UCHAR *lpCondition, UCHAR *lpFilename, UCHAR *lpFunctionname, ULONG ulLineNo)
and to use the macro we will insert a line like this:
NHPOS_ASSERT_TEXT(sBRetCode >= 0, "CliEtkTimeIn(): EtkTimeIn() returned error");
What this macro will do is that if the return code is less than 0 (the assertion fails), a log will be generated with the provided text. The log includes the condition that generated the log along with file name and line number.
The function PifLogAbort() generates logs with a specified length and treats the output file as a circular buffer. The logs have a time and date stamp as well.
In those cases where we want to generate the descriptive text dynamically at run time, perhaps to provide the actual error code value, we use the sprintf() function with a buffer as in the following code sequence:
if (sErrorSave != STUB_BM_DOWN) {
char xBuff[128];
sprintf(xBuff, "CstSendBMasterFH: CstComReadStatus() - 0x%x, sError = %d", usCstComReadStatus, CliMsg.sError);
NHPOS_ASSERT_TEXT((sErrorSave == STUB_BM_DOWN), xBuff);
}
If we want the logs to not be generated, all we need to do is to go to the single header file where the macro is defined and define it to be nothing then recompile. However we have found that these logs can be very valuable when investigating field issues and are especially useful during integration testing.
Windows Events are a potential replacement for TRACE macros, depending on your particular scenario. The code gets compiled into both Debug and Release configurations. Event tracing can then be dynamically enabled and disabled, displayed in real-time, or dumped on a client's machine for later diagnosis. The traces can be correlated with trace information gathered from other parts of the OS as well.
If you merely need to dump information whenever code reaches certain checkpoints, together with variable content, stack traces, or caller names, Visual Studio's Tracepoints are a non-intrusive option to do so.