I wonder if there is way to define your own debug flags in VS for C++.
For example the code below is only executed in debug mode. I want to have another piece of code that maybe prints "Hello World"that only prints at debug level 2. How do you define a level 2 debug flag in VS? is it via properties?
#ifdef _DEBUG
std::cout << "Hello" << std::endl;
#endif
You use your own macros.
#ifdef DEBUG_LEVEL_2
std::cout << "Hello" << std::endl;
#endif
or
#if defined (DEBUG_LEVEL) && DEBUG_LEVEL >= 2
std::cout << "Hello" << std::endl;
#endif
and then you either
#define DEBUG_LEVEL_2
or
#define DEBUG_LEVEL 2
manually, or define it in the "Preprocessor" tab in the project settings, or pass it to the compiler using the /Dflag if you're compiling on the command line.
Related
In VS Code I have a define identifier that is not found. The variable is eventually passed to the compiler as a flag -DENABLE_LOGS_PREVIEW and found in ./cmake-build-debug/build.ninja. I build with CMake and Ninja directly from the command line.
#ifdef ENABLE_LOGS_PREVIEW
std::cout << "Hello world" << std::endl;
#endif
std::cout << "Goodbye world" << std::endl;
Correctly prints, though VS Code greys out std::cout << "Hello world" << std::endl;
Hello world
Goodbye world
I'm struggling to get the correct c_cpp_properties.json to work with my workflow. How do I get the above define to be recognized?
The answer here was to have CMake to generate a compile_commands.json and add it to the VS Code c_cpp_properties.json like so:
"compileCommands": "${workspaceFolder}/cmake-build-debug/compile_commands.json"
With errno, I am trying to check if cmath functions produce a valid result. But even after I put a negative value in sqrt() or log(), errno stays at value 0.
Can anyone know why, and how I can make errno behave correctly?
The environment is macOS Monterey version 12.6.1, the compiler is gcc version 11.3.0 (Homebrew GCC 11.3.0_1) or Apple clang version 14.0.0 (clang-1400.0.29.202) (I tried the 2 compilers).
The compile command is g++ test_errno.cpp -o test_errno -std=c++14.
The piece of code I tried is directly copied from this page. The following is the code.
#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <clocale>
int main()
{
double not_a_number = std::log(-1.0);
std::cout << not_a_number << '\n';
if (errno == EDOM) {
std::cout << "log(-1) failed: " << std::strerror(errno) << '\n';
std::setlocale(LC_MESSAGES, "de_DE.utf8");
std::cout << "Or, in German, " << std::strerror(errno) << '\n';
}
}
Its result didn't print the error messages, which should be printed if errno is set correctly.
It seems that on macOS, errno is not used, from this bug report from #GAVD's comment.
I could check that via math_errhandling value from #Pete Becker's comment.
It seems there are 2 ways of math error handling in C/C++, either with errno, or with floating-point exception, as the 2nd link above shows.
We can check which way (or both of them) the system's math library employs, via checking if macro constant math_errhandling is equal to MATH_ERREXCEPT or MATH_ERRNO, like the following (copied from the 2nd link):
std::cout << "MATH_ERRNO is "
<< (math_errhandling & MATH_ERRNO ? "set" : "not set") << '\n'
<< "MATH_ERREXCEPT is "
<< (math_errhandling & MATH_ERREXCEPT ? "set" : "not set") << '\n';
And on my system, the output is
MATH_ERRNO is not set
MATH_ERREXCEPT is set
, which means the system does not use errno for reporting math errors, but use floating-point exception.
That's why errno stays at value 0 no matter what, and I should have used std::fetestexcept() to check error conditions.
With floating-point exceptions, std::feclearexcept(FE_ALL_EXCEPT); corresponds to errno = 0;, and std::fetestexcept(FE_DIVBYZERO) corresponds to errno == ERANGE for example.
I'm going to take a stab in the dark and guess you are enabling fast-math in your build?
Without fast-math:
https://godbolt.org/z/vMo1P7Mn1
With fast-math:
https://godbolt.org/z/jEsGz7n38
The error handling within cmath tends to break things like vectorisation & constexpr (setting external global variables, is a side effect that breaks both cases). As a result, you are usually better off checking for domain errors yourself...
I sometimes use the class DOut (listed below) for debugging
#include<fstream>
#include<iostream>
#include<sstream>
#define WIN32_LEAN_AND_MEAN
#include<Windows.h>
#ifdef UNICODE
#define tostream wostream
#define tostringstream wostringstream
#define _T(x) L##x
#else
#define tostream ostream
#define tostringstream ostringstream
#define _T(x) x
#endif
class DOut : public std::tostringstream
{
public:
//http://stackoverflow.com/questions/2212776/overload-handling-of-stdendl
DOut& operator << (std::tostream&(*f)(std::tostream&))
{
if (f == std::endl)
{
*this << _T("\n");
OutputDebugString(str().c_str());
str(_T(""));
}
else
{
*this << f;
}
return *this;
}
//https://hbfs.wordpress.com/2010/12/21/c-logging/
template <typename TT>
inline DOut & operator << (const TT& t)
{
(*(std::tostringstream*) this) << t;
return *this;
}
};
int main()
{
DOut dout;
int x = 20;
dout << "x = " << x << std::endl;
dout << "x * x = " << x * x << std::endl;
dout << "hexq=" << x*x << "=" << std::hex << x * x << std::endl;
}
It works quite well except it gets interleaved with all the VS output information. For example
'dout.exe': Loaded 'U:\GCS\test\dout\Debug\dout.exe', Symbols loaded.
'dout.exe': Loaded 'C:\WINDOWS\system32\ntdll.dll'
'dout.exe': Loaded 'C:\WINDOWS\system32\kernel32.dll'
'dout.exe': Loaded 'C:\WINDOWS\WinSxS\x86_Microsoft.VC90.DebugCRT_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_f863c71f\msvcp90d.dll'
'dout.exe': Loaded 'C:\WINDOWS\WinSxS\x86_Microsoft.VC90.DebugCRT_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_f863c71f\msvcr90d.dll'
x = 20
x * x = 400
hexq=400=190
The program '[3108] dout.exe: Native' has exited with code 0 (0x0).
The above is not strictly accurate as I don't know how to get stackoverflow to display monochrome text. All the text is just in a single colour. I could always output it to a file but this is convenient as I don't always have a console window and I don't have to worry about chdirs which change where the output file is written to.
I just wondering whether it is possible to output my debug information in a different colour. I've tried ANSI escape sequences but they don't work.
If I understand you right, you can do such things with help of extensions: VSColorOutput or VSCommands for Visual Studio
They can change appearance in the output window. You can use out of the box behavior or add some special characters when outputting with DOut class and create own rule how to color it.
VSColorOutput hooks into the the classifier chain of Visual Studio. This allows VSColorOutput to monitor every line sent to the output window. A list of classifiers, consisting of regular expressions and classifications is checked. The first matching expression determines the classification the line of text. If no patterns match, then line is classified as a common build text.
Actually, the answer is easier than I thought. Just right click in the output window and select Program Output. It just shows you the program output without all the other bits. No need for colours.
Also, it is available from VS2005 up to the current version without any need for installing different Visual Studio extensions for the different versions of VS.
Some systems I use don't have a logging library I'm using, which is OK for well-tested code on production runs --- the logging library is mostly for debugging and testing. On my main development machine, and on a couple of servers I frequently run experiments on, the logging library exists. But occasionally I need to farm out experiments to another server with many more nodes and cores but that does not have the logging library.
The library (Google glog) provides, for example, the following macro functions:
LOG(INFO) << "Insert my message here.";
LOG(FATAL) << "Insert another message here.";
So, what I've done is defined the following:
#ifdef NOLOGGING
#define MYLOG(i,m) std::cerr << #i << ": " << m << "\n";
#else
#define MYLOG(i,m) LOG(i) << m ;
#endif
Using those definitions, I can now write statements like this:
MYLOG(INFO, "My info message");
MYLOG(FATAL,"My fatal message");
If compiled with flag -DNOLOGGING, the last two statements will be expanded to:
std::cerr << "INFO" << ": " << "My info message" << "\n";
std::cerr << "FATAL" << ": " << "My fatal message" << "\n";
Wherease, if the -DNOLOGGING flag is not used in compilation, they will be expanded to:
LOG(INFO) << "My info message";
LOG(FATAL) << "My fatal message";
The solution I've described above is satisfactory, but not ideal.
Ideally, when I don't have acces to the logging library, statements like MYLOG(FATAL,"foo") would expand to statements that print to std::cerr; however, statments like MYLOG(INFO,"bar") would expand to nothing. In other words, when I can't use the logging library, I want statements like MYLOG(INFO,"bar") to be ignored. The idea is that I don't care too much about log messages of the INFO severity when I'm using the servers without the logging library, but I do still want to see messages of the FATAL severity.
How, if possible, can I do this using only preprocessor directives?
I don't think you can do it solely with preprocessing directives, since the preprocessor doesn't really give you the necessary mechanisms to guide macro expansion based on the arguments to the macro.
That said, you can perpetrate some mildly ugly hacks that will work. Consider the following code:
#include <iostream>
#define MYLOG_ERR 1
#define MYLOG_INFO 0
#define P(a,b) a##b
#define MYLOG(x,y) do { if (P(MYLOG_,x)) { std::cerr << y << std::endl; } } while (0)
int main(void)
{
MYLOG(ERR, "err");
MYLOG(INFO, "info");
}
This approach relies on the compiler's optimizer to recognize some common idioms, such as do { ... } while (0) and if (0) / if (1) to optimize away compile-time known conditions. But, I think it'll give you what you want.
#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.