How to process C++ file to remove ifdef'd out code - c++

I have inherited a piece of C++ code which has many #ifdef branches to adjust the behaviour depending on the platform (#ifdef __WIN32, #ifdef __APPLE__, etc.). The code is unreadable in its current form because these preprocessor directives are nested, occur in the middle of functions and even in the middle of multi-line statements.
I'm looking for a way of somehow specifying some preprocessor tags and getting out a copy of the code as if the code had been pre-processed with those flags. I'd like the #include directives to be left untouched, though.
Example:
#include <iostream>
#ifdef __APPLE__
std::cout << "This is Apple!" << std::endl;
#elif __WIN32
std::cout << "This is Windows" << std::endl;
#endif
would turn into:
#include <iostream>
std::cout << "This is Apple!" << std::endl;
after being processed by: tool_i_want example.cpp __APPLE__.
I've hacked a quick script that does something similar, but I'd like to know of better tested and more thorough tools. I am running a Linux distribution.
I have decided against just running the C-preprocessor because if I'm not mistaken it will expand the header files, which would make everything more unreadable.

Use unifdef. It is designed for that purpose.

Complementing Basile Starynkevitch's answer, I want to mention coan. The major advantage is that, when used with -m it does not require the user to unset all symbols they want undefined.
This code:
#include <iostream>
#ifdef __ANDROID__
std::cout << "In Android" << std::endl;
#endif
#ifndef __WIN32
std::cout << "Not a Windows platform" << std::endl;
#endif
#ifdef __APPLE__
std::cout << "In an Apple platform" << std::endl;
#elif __linux__
std::cout << "In a Linux platform" << std::endl;
#endif
would result in this code if simply run as: unifdef -D__APPLE__ example.cpp:
#include <iostream>
#ifdef __ANDROID__
std::cout << "In Android" << std::endl;
#endif
#ifndef __WIN32
std::cout << "Not a Windows platform" << std::endl;
#endif
std::cout << "In an Apple platform" << std::endl;
Using unifdef one would need to use
unifdef -D__APPLE__ -U__ANDROID__ -U__WIN32 -U__linux__ example.cpp:
#include <iostream>
std::cout << "Not a Windows platform" << std::endl;
std::cout << "In an Apple platform" << std::endl;
This can get exhausting quickly when dealing with code considering several different platforms. With coan it's a matter of:
coan source -D__APPLE__ -m example.cpp.

Related

Having difficulty using a debugger macro

Here is the code:
void DBG() { cerr << "]" << endl; }
template<class H, class... T> void DBG(H h, T... t) {
cerr << to_string(h); if (sizeof...(t)) cerr << ", ";
DBG(t...); }
#ifdef _DEBUG
#define dbg(...) cerr << "LINE(" << __LINE__ << ") -> [" << #__VA_ARGS__ << "]: [", DBG(__VA_ARGS__)
#else
#define dbg(...) 0
#endif
Im currently using g++ on vs code on a mac and whenever I run my program using this and for example
I write dbg(10) on main the program does not even run and does not do anything(it outputs nothing).
How can I change this code so it would work on g++ without having to download clang?
Note: I saw some people use #ifdef LOCAL instead of #ifdef _DEBUG but it still doesn't work for me(does not output anything). How do I get #ifdef LOCAL or #ifdef _DEBUG to work on g++?

using stream to log information in C++

I have a C++ class which logs messages to a std::ofstream. In the class definition is this code:
#ifdef NDEBUG
#define FOO_LOG(msg) /* calls to log messages are no-op in release mode */
#else
std::ofstream log_stream;
#define FOO_LOG(msg) if (log_stream.is_open()) { log_stream << msg << std::endl; }
#endif
The constructor for that class has several things it checks, and in certain situations will open the log file similar to this:
#ifndef NDEBUG
log_stream.open("output.log");
#endif
Then in the code, it calls the C macro like this:
FOO_LOG("stuff=" << stuff << " in loop counter #" << xyz)
It is convenient that you can pass multiple params to the FOO_LOG() macro. There are obvious limitations, like when logging messages from multiple threads, but this is only used for simple logging in debug builds.
What I want to know is whether there is a different/better way to deal with the msg parameter in C++? Is there a simpler/cleaner way to implement something similar to FOO_LOG() in C++?
Instead of having #ifdef NDEBUG everywhere in your code you can have a #ifdef NDEBUG at the start of the header to define other useful macros.
For me FOO_LOG("stuff=" << stuff << " in loop counter #" << xyz); feels a bit unnatural. I would have to keep reffering back to the macro definition to see how it's implemented. Instead you can define a macro to behave as an std::ostream and use it as you would any other stream. That way you can do stuff like LOG_STREAM << "stuff=" << stuff << " in loop counter #" << xyz << std::endl;.
For this answer I had some inspiration from this question.
#include <fstream>
#define NDEBUG
//An ostream class that does nothing
class DummyStream : public std::ostream {
public:
int overflow(int c) { return c; }
} dummyStream;
//Here we let NDEBUG define other macros.
#ifdef NDEBUG
std::ofstream logStream;
std::ostream& oLogStream(*(std::ostream*)&logStream);
#define LOG_STREAM (logStream.is_open() ? oLogStream : dummyStream)
#define OPEN_LOG(log) (logStream.is_open() ? logStream.close(), logStream.open(log, std::ofstream::out | std::ofstream::app) : \
logStream.open(log, std::ofstream::out | std::ofstream::app))
#define CLOSE_LOG() (logStream.close())
#else
#define LOG_STREAM (dummyStream)
#define OPEN_LOG(log) //no-op
#define CLOSE_LOG() //no-op
#endif // NDEBUG
int main(int argc, char* argv[]) {
//will only log if NDEBUG is defined.
OPEN_LOG("log.txt");
std::string stuff("stuff to log");
for(int xyz = 0; xyz < 4; xyz++) {
LOG_STREAM << "stuff=" << stuff << " in loop counter #" << xyz << std::endl;
}
CLOSE_LOG();
//Log is not open so it will not log anything.
stuff = "stuff to not log";
for(int xyz = 0; xyz < 4; xyz++) {
LOG_STREAM << "stuff=" << stuff << " in loop counter #" << xyz << std::endl;
}
return 0;
}
Benifits of this?
LOG_STREAM is treated more intuitively like any other stream.
OPEN_LOG(log) will close already open logs before opening a new one and when NDEBUG is not define it will do nothing.
CLOSE_LOG() will close a log and when NDEBUG is not define it will do nothing.
Don't need to type #ifdef NDEBUG ... #endif everywhere.
dummyStream can be replaced with something like std::cout or some other stream.
Down side?
You have this DummyStream that's just in your code and a few no-op's are performed when LOG_STREAM is used when NDEBUG is not defined.

Visual Studio C++ code how to autoindent preprocessor directives

How to use autoindent the preprocessor directives
For example in Visual studio all preprocessor directives intended like
this
void test(){
#if _SOME_VAR
std::cout << "test" << std::endl;
#if _SOME_VAR2
std::cout << "test2" << std::endl;
#endif
#endif
}
How can i make code auto indents like this
void test(){
#if _SOME_VAR
std::cout << "test" << std::endl;
#if _SOME_VAR2
std::cout << "test2" << std::endl;
#endif
#endif
}
The solution is
Tools->Options->Text Editor->Indentation->Position of preprocessor
directives

string conversion with boost locale: different behaviour on windows and linux

This is my sample code:
#pragma execution_character_set("utf-8")
#include <boost/locale.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <iostream>
int main()
{
std::locale loc = boost::locale::generator().generate("");
std::locale::global(loc);
#ifdef MSVC
std::cout << boost::locale::conv::from_utf("grüßen vs ", "ISO8859-15");
std::cout << boost::locale::conv::from_utf(boost::locale::to_upper("grüßen"), "ISO8859-15") << std::endl;
std::cout << boost::locale::conv::from_utf(boost::locale::fold_case("grüßen"), "ISO8859-15") << std::endl;
std::cout << boost::locale::conv::from_utf(boost::locale::normalize("grüßen", boost::locale::norm_nfd), "ISO8859-15") << std::endl;
#else
std::cout << "grüßen vs ";
std::cout << boost::locale::to_upper("grüßen") << std::endl;
std::cout << boost::locale::fold_case("grüßen") << std::endl;
std::cout << boost::locale::normalize("grüßen", boost::locale::norm_nfd) << std::endl;
#endif
return 0;
}
Output on Windows 7 is:
grüßen vs GRÜßEN
grüßen
grußen
Output on Linux (openSuSE 12.3) is:
grüßen vs GRÜSSEN
grüssen
grüßen
On Linux the german letter 'ß' is converted to 'SS' as predicted, while this character remains unchanged on Windows.
Question: why is this so? How can I correct the conversion?
Some notes: Windows console codepage is set to 1252. In both cases locales are set to de_DE. I tried to replace the default locale setting in the listing above by "de_DE.UTF-8" - without any effect.
On Windows this code is compiled with Visual Studio 2013, on Linux with GCC 4.7, c++11 enabled.
Any suggestions are appreciated - thanks in advance for your support!
Windows doesn't do this conversion because "it would be too confusing" for developers if the string length changed all of a sudden. And boost presumably just delegates all the Unicode conversions to the underlying Windows APIs
Source
I guess the robust way to handle it would be to use a third-party Unicode library such as ICU.

enable debugf in SystemC

I was looking at the source of SystemC and saw that there are things like:
#define DEBUGF \
if (0) std::cout << "sc_cor_pthread.cpp(" << __LINE__ << ") "
and later on there are lines such as:
DEBUGF << this << ": sc_cor_pthread::sc_cor_pthread()" << std::endl;
(these are from sc_cor_pthread.cpp)
I have already enabled debug option when configuring using ../configure --enable-debug but it doesn't seem to activate these kinds of stuff. How am I supposed to turn these on instead of manually modifying source?
Add this to your compile line:
-DDEBUGF