I want to put some warning or error into my code. I am using visual studio 2010.
I used #error and #warning in Xcode, but visual studio doesn't know those directives.
After some searching through different articles, I finally came to this solution which works in Visual Studio 2010:
#define STRINGIZE_HELPER(x) #x
#define STRINGIZE(x) STRINGIZE_HELPER(x)
#define __MESSAGE(text) __pragma( message(__FILE__ "(" STRINGIZE(__LINE__) ")" text) )
#define WARNING(text) __MESSAGE( " : Warning: " #text )
#define ERROR(text) __MESSAGE( " : Error: " #text )
#define MESSAGE(text) __MESSAGE( ": " #text )
#define TODO(text) WARNING( TODO: text )
and you can use it as:
WARNING( This will be a compiler warning );
ERROR( This will be a compiler error );
MESSAGE( Well this is what I have to say about this code );
TODO( Still have to fix 3D rendering );
Note that TODO() will also generate a compiler warning; if you don't want to register your TODOs as warnings just use this instead:
#define TODO(text) MESSAGE( TODO: text )
If you want to display function name inside warnings/errors/TODOs, use this instead:
#define WARNING(text) __MESSAGE( " : Warning: (" __FUNCTION__ "): " #text )
#define ERROR(text) __MESSAGE( " : Error: (" __FUNCTION__ "): " #text )
#define MESSAGE(text) __MESSAGE( ": (" __FUNCTION__ "): " #text )
#define TODO(text) __MESSAGE( " : Warning: TODO: (" __FUNCTION__ ") " #text )
This suggestion is a bit late I know, but...
You can achieve what you want with the following trick:
// stringised version of line number (must be done in two steps)
#define STRINGISE(N) #N
#define EXPAND_THEN_STRINGISE(N) STRINGISE(N)
#define __LINE_STR__ EXPAND_THEN_STRINGISE(__LINE__)
// MSVC-suitable routines for formatting <#pragma message>
#define __LOC__ __FILE__ "(" __LINE_STR__ ")"
#define __OUTPUT_FORMAT__(type) __LOC__ " : " type " : "
// specific message types for <#pragma message>
#define __WARN__ __OUTPUT_FORMAT__("warning")
#define __ERR__ __OUTPUT_FORMAT__("error")
#define __MSG__ __OUTPUT_FORMAT__("programmer's message")
#define __TODO__ __OUTPUT_FORMAT__("to do")
Then to generate a message, do e.g.:
#pragma message ( __MSG__ "my message" )
(From http://rhubbarb.wordpress.com/2009/04/08/user-compilation-messages-c-or-c/)
didn't find anything about warning message but MSVC has creates compile errors just like xcode '#error message` according to msdn page
The way it works for me:
#define _message_ "Warning Msg: "
#pragma message(_message_"Need to do something")
You can use #pragma warning ...
Mandatory read
MSVC uses
#pragma error( "message" )
and
#pragma warning( "message" )
directives, whereas GCC leaves out the pragmas.
why don't you use
#warning WarningMessage
or may be
#error ErrorMessage
Related
I need a Boost logger which logs to console (and later on to a file), with following parameters:
"[%TimeStamp%] [%Severity%] [%File%(%Line%)] %Message%".
I have read the Boost.Log v2 docs and got some "inspiraton" from other places but I can't really get this to work.
// cswlogger.h
#pragma once
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/attributes/mutable_constant.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/utility/manipulators/add_value.hpp>
BOOST_LOG_GLOBAL_LOGGER(sysLogger,
boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level>);
class CswLogger
{
public:
/// Init with default info level logging
static void init(boost::log::trivial::severity_level level = boost::log::trivial::info);
/// Disable logging
static void disable();
};
#define LOG_LOG_LOCATION(LOGGER, LEVEL, ARG) \
BOOST_LOG_SEV(LOGGER, boost::log::trivial::LEVEL) \
<< boost::log::add_value("Line", __LINE__) \
<< boost::log::add_value("File", __FILE__) << ARG
/// System Log macros.
/// TRACE < DEBUG < INFO < WARN < ERROR < FATAL
#define LOG_TRACE(ARG) LOG_LOG_LOCATION(sysLogger::get(), trace, ARG);
#define LOG_DEBUG(ARG) LOG_LOG_LOCATION(sysLogger::get(), debug, ARG);
#define LOG_INFO(ARG) LOG_LOG_LOCATION(sysLogger::get(), info, ARG);
#define LOG_WARN(ARG) LOG_LOG_LOCATION(sysLogger::get(), warning, ARG);
#define LOG_ERROR(ARG) LOG_LOG_LOCATION(sysLogger::get(), error, ARG);
#define LOG_FATAL(ARG) LOG_LOG_LOCATION(sysLogger::get(), fatal, ARG);
And source file:
// cswlogger.cpp
#include "cswlogger.h"
#include <boost/log/core.hpp>
#include <boost/log/common.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/settings.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
BOOST_LOG_GLOBAL_LOGGER_DEFAULT(sysLogger,
boost::log::sources::severity_channel_logger_mt<boost::log::trivial::severity_level>);
void CswLogger::init(boost::log::trivial::severity_level level)
{
boost::log::add_console_log
(
std::clog,
boost::log::keywords::format = "[%TimeStamp%] [%Severity%] [%File%(%Line%)] %Message%"
);
boost::log::core::get()->set_filter
(
boost::log::trivial::severity >= level
);
// Indicate start of logging
LOG_INFO("Log Start");
}
void CswLogger::disable()
{
boost::log::core::get()->set_logging_enabled(false);
}
main.cpp
#include "cswlogger.h"
CswLogger::init();
LOG_INFO("This is a info trace");
The output of this will be: "[ ] [ ] main.cpp(3) This is a info trace"
The Timestamp and Severity paramaters are missing.
Is it possible to use the "BOOST_LOG_SEV" log macro and add custom log parameters or do I need to use another approach?
First, the TimeStamp attribute is missing in the output because you haven't added it to the logging core. You can add it as described here:
boost::log::core::get()->add_global_attribute(
"TimeStamp",
boost::log::attributes::local_clock());
Or you could add it as one of the commonly used attributes by calling add_common_attributes.
Next, the Severity attribute is present, it is provided by the logger. However, the value type of that attribute (which is boost::log::trivial::severity_level) is not supported by default for filters and formatters parsed from strings. You can solve this in two ways.
First, you can switch to the manual setup of the logging sinks, which will allow you to set the filter and formatter for the sink as a lambda expression. This way you will be able to provide the attribute type to the formatter. For example:
BOOST_LOG_ATTRIBUTE_KEYWORD(a_timestamp, "TimeStamp", boost::log::attributes::local_clock::value_type)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_severity, "Severity", boost::log::trivial::severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_file, "File", std::string)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_line, "Line", int)
typedef boost::log::sinks::synchronous_sink< boost::log::sinks::text_ostream_backend > sink_t;
auto sink = boost::make_shared< sink_t >();
sink->set_formatter(boost::log::expressions::ostream
<< "[" << a_timestamp << "] "
<< "[" << a_severity << "] "
<< "[" << a_file << "(" << a_line << ")] "
<< boost::log::expressions::message);
boost::log::core::get()->add_sink(sink);
Alternatively, you can register the formatter and filter factories for the Severity attribute so that the formatter and filter parsers are able to associate that attribute with the boost::log::trivial::severity_level type. This is described in detail here. In your case, you can just add this call before any formatters are parsed (i.e. before the add_console_log call):
boost::log::register_simple_formatter_factory<
boost::log::trivial::severity_level, char >("Severity");
I'm compiling the following C++ code in Visual Studio 2015 (update 3):
#include <iostream>
using namespace std;
////////////////////////////////////////
#define UNDERSCORE1(a,b) a ## _ ## b
#define UNDERSCORE(a,b) UNDERSCORE1(a,b)
#define STRINGIFY1(x) #x
#define STRINGIFY(x) STRINGIFY1(x)
#define VALUE(x) UNDERSCORE(x, VALUE)
#define NEXT(x) (VALUE(x) + 1)
/////////////////////////////////////////
#define X1_VALUE 0
#define X2_VALUE NEXT(X1)
#define X3_VALUE NEXT(X2)
#define TOTAL NEXT(X3)
int main() {
cout << STRINGIFY(TOTAL) << endl;
cout << TOTAL << endl;
return 0;
}
The result printed to stdout is very strange:
(X3_VALUE + 1)
3
When trying the same on gcc, build fails (expectedly).
When commenting out cout << TOTAL << endl; I get something different altogether:
(NEXT(X2) + 1)
Actually gcc behavior makes sense, since NEXT macro is called recursively: NEXT(X3) is expanded to X3_VALUE which in turn expands to NEXT(X2), so the second expansion of NEXT macro (NEXT(X2)) is not performed.
What doesn't make sense is Visual Studio behavior:
When printing the macro TOTAL using STRINGIFY, NEXT seems to be expanded twice to yield X3_VALUE.
When compiling the macro TOTAL directly to send it to cout, NEXT is expanded all the way! As if the preprocessor ran multiple times to recursively expand NEXT.
Another thing I tried was to compile this code in Visual Studio with the /P compiler option, to get the preprocessed code:
int main() {
cout << "(X3_VALUE + 1)" << endl;
cout << (((0 + 1) + 1) + 1) << endl;
return 0;
}
So is it, as I suspect, a bug in Visual Studio preprocessor? Or a legit undefined behavior?
Perhaps this behavior can be abused to truly expand macros recursively? I know that a limited recursion is possible with some tricks but is limited to a predefined number of scans. In this case I did not observe a limit to the number of times NEXT is expanded.
As Hans mentioned in the comments, the MSVC preprocessor is not conformant.
You can enable the conformant preprocessor with -experimental:preprocessor.
Here is a simplified repro + solution: https://godbolt.org/z/7u_-bH
The accepted answer to the question C++ concatenating __FILE__ and __LINE__ macros? work for FILE and LINE, but I would like to add the func macro too.
#define S1(x) #x
#define S2(x) S1(x)
#define S3(x) x
#define LOCATION __FILE__ " : " S3(__func__) " : " S2(__LINE__)
this gives error
log.cpp|15 col 15 error| note: in definition of macro ‘S3’
Also tried,
#define LOCATION __FILE__ " : " __func__ " : " S2(__LINE__)
gives error
log.cpp|30 col 9 error| note: in expansion of macro ‘LOCATION’
I understand that LINE was a integer hence needed #x, but func is a char array. How do I get this working? Any help?
As cpplearner mentioned correctly __func__ is not a macro, it's a special function-local predefined variable. I achieved desired result by
#define S1(x) #x
#define S2(x) S1(x)
#define LOCATION string(__func__) + " : " S2(__LINE__) + " : "
and I use it by sending the string to a wrapper log function
void log(string s) {
cout << s <<endl;
}
void abc(){
log(LOCATION + string("some message "));
}
Outputs:
abc : 23 : some message
__func__ is a variable (not a macro unlike __FILE__ or __LINE__)
This related question Treating __func__ as a string literal instead of a predefined identifier has good explanation.
I've seen this, but none of the answers worked for VS2010. The constant's (or should I call it variable?) numerical value didn't get displayed
This line of code #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX is turning out to be true when I'm actually programming in windows. I need to see the value of OGRE_PLATFORM_WIN32 and OGRE_PLATFORM_LINUX during the build process itself. Could you help with how to go about it?
You can check the preprocessor output using:
/E - preprocess to stdout or
/P - preprocess to file or
/EP - preprocess to stdout without #line directives
options in visual studio
First, check the preprocessor defines in project options - active configuration and all configurations, and make sure the right things are defined.
If you are still having problems, try substituting this for your main method:
#include <iostream>
int main()
{
#ifdef OGRE_PLATFORM_LINUX
std::cout << "OGRE_PLATFORM_LINUX = " << OGRE_PLATFORM_LINUX << "\n";
#else
std::cout << "OGRE_PLATFORM_LINUX not defined.\n";
#endif
#ifdef OGRE_PLATFORM_WIN32
std::cout << "OGRE_PLATFORM_WIN32 = " << OGRE_PLATFORM_WIN32 << "\n";
#else
std::cout << "OGRE_PLATFORM_WIN32 not defined.\n";
#endif
#ifdef OGRE_PLATFORM
std::cout << "OGRE_PLATFORM = " << OGRE_PLATFORM << "\n";
#else
std::cout << "OGRE_PLATFORM not defined.\n";
#endif
return 0;
}
Also, did you create the project, was it created by some type of pre-make (CMake, automake, etc) system, did you download it from somewhere? If you didn't create it, somebody could have ported over some Linux code without checking their preprocessor options.
I would like to know why the Visual C++ compiler gets me an warning/error if I use the following code:
#pragma message( "You have " _MSC_FULL_VER )
Here is what I get:
error C2220: warning treated as error - no 'object' file generated
warning C4081: expected ':'; found ')'
The problem reproduces for _MSC_FULL_VER or _MSV_VER but not if I try to use others like __FILE__ or __DATE__.
These macros are defined, they are documented on msdn
I think #pragma message needs C strings only. IIRC, _MSC_FULL_VER is a number, while __FILE__ and __DATE__ are C strings. Try this
// BEWARE! Untested macro hackery ahead!
#define STRINGIFY( L ) #L
#define MAKESTRING( M, L ) M(L)
#define STRINGIZE(X) MAKESTRING( STRINGIFY, X )
#pragma message( "You have " STRINGIZE(_MSC_FULL_VER) )
(On a side note, this allows
#define SHOWORIGIN __FILE__ "(" STRINGIZE(__LINE__) "): "
#pragma message( SHOWORIGIN "your message here" )
which allows you to double-click on a message in VS's output pane and be taken to its file/line.)