I am experimenting to change some of the current code in a library that returns an enum for status code to a class type that has status and sub-status as shown below in status class below. One of the requirements is to have this work with lot of existing code that uses the type in == and != kind of checks all over the code base. Another requirement is to be able to use it existing printf statements all over the place.
I converted the enum to #define as below and then used operator overloading for == (will have to implement inequality later). I was expecting the printf() usage shown below to fail when I try to print status. However, surprisingly that seems to be working and printing the status_ member field value already !! How is it working ? Can someone please help make it make sense ?
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
// these are the status codes that any function can return
// for example test_function() below returns one of these
#define STATUS_OK 100
#define STATUS_ERR 200
// this is the new class that replaces the enum types
class status {
public:
status() {}
status(unsigned int status) : status_(status) {}
status(unsigned int status, unsigned int sub_status) : status_(status), sub_status_(sub_status) {}
bool operator==(const status& other) {
return (status_ == other.status_);
}
private:
unsigned int status_;
unsigned int sub_status_; // sub_status_ is meant for future usage
};
// helper function to test the main code
// this returns possible status codes
status
test_function (void)
{
int r1, r2;
r1 = rand();
r2 = rand();
if (r1 > r2) {
return STATUS_OK;
}
return STATUS_ERR;
}
int
main ()
{
status ret;
srand(time(0));
ret = test_function();
printf("ret is %u\n", ret); // how is this already working ?? %u should expect unsigned int ??
if (ret == STATUS_OK) {
printf("ret is OK\n");
} else {
printf("ret is not OK\n");
}
return 0;
}
A sample runs print the following:
# ./a.out
ret is 200. <== what makes this work ? how is class type getting converted to integer?
ret is not OK
# ./a.out
ret is 100
ret is OK
As a follow up question, is there anything in the status class that I can do to make printf() legitimately work work this way ? This is convenient as I can avoid touching lot of code.
Printf takes the bytes at the beginning of the class and casts them to the specified type ("u") itself, and does not call any class methods, including the () operator.
You can't make your class work with printf by changing only the class, since it's a C language function and not C++, that interprets your class in memory as a simple collection of bytes without any internal structure (void*), i.e. it doesn't call conversion operators to type. Your code works because the class is two consecutive unsigned int fields status_ and sub_status_ . printf, seeing the format flag "u", takes the zero offset of the class field with the size and type of unsigned int, which completely coincides with the status_ field. If you add another field in the class before this field, for example "unsigned int constant_ = 5;", then 5 will always be displayed, since now it will be located at the beginning. If the field size does not match the printf output format or a virtual method table appears in the class, then your output can be anything.
To avoid this, you must explicitly define how to print your class, in order to do this:
use std::cout, in other words replace printf("ret is %u\n", ret); with std::cout << "ret is " << ret << std::endl;
add a public method in the class to get the status code:
unsigned int status_value() const
{
return status_;
}
add a function after the class declaration to define the output of your class to the output stream:
std::ostream& operator<<(std::ostream& stream, const status& s)
{
stream << s.status_value();
return stream;
}
Then you will have a predictable result.
If you want minimal work on your printf calls, you can add only a conversion operator to unsigned int in the class:
operator unsigned int() const
{
return status_;
}
Then you only have to cast your class to unsigned int:
printf("ret is %u\n", (unsigned int)ret);
printf("ret is %u\n", static_cast<unsigned int>(ret));
Or add and use a public method to get the status code:
printf("ret is %u\n", ret.status_value());
printf's %u specifier expects an unsigned int. Passing it a different type as argument (after default argument promotions) causes undefined behavior.
That is the case here.
printf is not extendable. You can either write your own function wrapping printf and interpreting the format string (not recommended) or use std::cout << with overloaded operator<< instead.
Or you can use fmtlib as alternative (also available as <format> in C++20).
Related
I want to write logger which would print logs to console using printf function.
Let's assume that I have following piece of code:
class Logger {
public:
Logger(std::string header = "") : header_(header) {}
template<class ...Args>
void LogInfo(const char* message, Args... args);
private:
std::string header_;
};
template<class ...Args>
void Logger::LogInfo(const char* message, Args... args) {
printf(message, args...);
}
This logs well but problem is when I call:
const char* s = "Monty Python";
Logger logger("[Header]");
logger.LogInfo("%d", s);
logger prints pointer-value without any warning, while printf call causes error (with my compilation flags)
error: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘const char*’ [-Werror=format=]
printf("%d", s);
The point of whole code is that I want to get this error during LogInfo call.
How can I do such a thing?
Falling back to printf function family and format strings brings you back quite a lot of issues concerning type safety You might be better off with modern C++ streaming mechanism. Sure, one wouldn't really want to log like this:
logger << "first: " << x << "second: " << y << commit;
So coming up with some alternative approach avoiding the problem with need for appropriate format string parameters; idea is the following:
arguments are inserted one after another at designated locations in the format string
insertion locations are identified by the character pattern %#
pattern %## suppresses argument insertion and is replaced with the insertion pattern as string
Disadvantage: we have to do the parsing ourselves:
void logInfo(char const* message)
{
char const* m = message;
while((m = strchr(m, '%')))
{
if(*++m == '#')
{
if(*++m != '#')
{
std::cout.write(message, m - message - 2);
std::cout << "<missing argument>";
}
else
{
std::cout.write(message, m - message);
++m;
}
message = m;
}
}
std::cout << message << std::endl;
}
template<typename A, typename ... AA>
void logInfo(char const* message, A a, AA ... aa)
{
char const* m = message;
while((m = strchr(m, '%')))
{
if(*++m == '#')
{
if(*++m != '#')
{
std::cout.write(message, m - message - 2);
std::cout << a;
return logInfo(m, aa...);
}
std::cout.write(message, m - message);
message = ++m;
}
}
std::cout << message << std::endl;
}
Sure, there is quite some common code yet, leaving to you to optimise, it's just for the idea...
Worked fine with the following examples:
logInfo("t1");
logInfo("t2", 7);
logInfo("t3: %#", 12);
logInfo("t4: %#%##", 10);
logInfo("t5: %#%%#", 12);
logInfo("t6: %#% baz", 10);
logInfo("t7 1: %# 2: %# 3: %#", 10, 12);
You might add further formatting options such as minimal output width, fill characters, precision, ... – just as printf provides as well...
Sure, this answer does not match exactly your question ("how to produce a warning"), instead, it simply makes the warning obsolete...
Ok, I hoped someone else said it, but I guess I'll be the one to bring macros...
#define LogInfo(logger, format, ...) printf("%s " format, logger.header().c_str(), __VA_ARGS__);
In order to illustrate what can be achieved, I assumed you wanted to add the logger header at each line. This is just an example.
You'd use it that way:
#include <cstdlib>
#include <string>
#include <iostream>
class Logger {
public:
Logger(std::string header = "") : header_(header) {}
std::string const& header() const { return header_; }
private:
std::string header_;
};
#define LogInfo(logger, format, ...) printf("%s " format, logger.header().c_str(), __VA_ARGS__);
int main()
{
const char* s = "Monty Python";
Logger logger("[Header]");
//LogInfo(logger, "%d", s); // error: format '%d' expects argument of type 'int', but argument 3 has type 'const char*' [-Werror=format=]
LogInfo(logger, "%s", s); // [Header] Monty Python
}
Demo: http://coliru.stacked-crooked.com/a/ad698776f2b0ed4f
As pointed out in comments the printf format errors can be used through the format attribute. But you have to loose the vardiag templates for that or add another level of indirection from the vardiac template function to a simple C vardiac function.
The format specifier is implicit in gcc (and other compilers) definition of printf and explicit for many other printf like functions. e.g.
extern int vsnprintf (char *__restrict __s, size_t __maxlen,
const char *__restrict __format, _G_va_list __arg)
__THROWNL __attribute__ ((__format__ (__printf__, 3, 0)));
Because of the attribute the vsnprintf will give the same warnings as a plain printf does. See the linked docs for how to specify the format attribuet for your function (after loosing the vardiac template). Note: Conversion to a plain vardiac function means you have to call vprintf using the varargs macros of the compiler.
The program fails while compiling the code. Compiler points to printf("Version = '%s'\n", gABXVER). I guess that I actually can't write gABXVER = "V1R1", but I don't have any other idea.
class CISPFVar_BINSTR : public CISPFVar
{
protected:
char* m_pBuffer;
long m_bDefined;
public:
...
void Initialize(char* szName, long lSize, int bDefineVar = 1)
{
Uninitialize();
ZStrToCharArray(szName, m_cName, 8);
m_Size = lSize+1;
m_pBuffer = (char*)malloc(m_Size);
m_pBuffer[0] = 0;
if (bDefineVar)
ISPLINK(__VDEFINE, m_cName, m_pBuffer, __BINSTR, &m_Size);
m_bDefined = bDefineVar;
}
...
};
CISPFVar_BINSTR gABXVER;
char szLoadLibraryPath[50];
int main(
int argc,
char* argv[])
{
if (argc > 1)
if (argv[1]) strcpy(szLoadLibraryPath, argv[1]);
gABXVER.Initialize("ABXVER",4);
gABXVER = "V1R1";
printf("Version = '%s'\n", gABXVER);
return 0;
};
When you use %s in printf family of functions, the corresponding argument type needs to be const char* or something that can be converted to const char*. The argument you are using is not such a type. Perhaps you meant to use:
printf("Version = '%s'\n", gABXVER.m_pBuffer);
The compiler should compile just fine (with possible warnings for printf) because printf doesn't care what you pass to it (beyond the first parameter) or whether it matches the format string. Modern compilers or error checking progs like lint will issue a warning if the params obviously don't match, and if you have a setting "treat warnings as errors", the prog may fail to compile.
That said, CISPFVar_BINSTR needs a public copy constructor if you want to pass it as a parameter by value to a function (because at least semantically a copy will be made). Does it have one? As others remarked it's customary to help your helpers by providing any information you have. Here we are badly missing the compiler errors. (You can edit your post at any time.)
I could imagine that the class has a conversion to char* or std::string, so it may suffice to try either printf("Version = '%s'\n", (char *)gABXVER) or printf("Version = '%s'\n", (std::string(gABXVER)).c_str() ).
You can only printf things that have format specifiers designed specifically for them. There is no format specifier that accepts a value of class type, so you cannot printf one directly.
The best thing you can do is explicitly convert your object to a const char* and pass the result to printf.
In c++ you can use many techniques to implement things like streaming operators
#include <iostream>
class Whatever
{
int value = 42;
public:
int Get() const {
return value;
}
friend std::ostream& operator<<(std::ostream&, Whatever const&);
};
std::ostream& operator<<(std::ostream& os, Whatever const& what) {
os << what.Get();
return os;
}
int main() {
Whatever x;
std::cout << x << std::endl;
}
printf is unsafe
In effect, you're doing serialization of your object into a readable string.
I have two functions with a little different functionality, so I can't make them as template functions.
int func64(__int64 a) {
return (int) a/2;
}
int func32(int a) {
return a--;
}
Depending on variable b64, I would like to call func64 or func32. I don't want check if b64 is true many times in my code, so I use pointers to functions.
void do_func(bool b64) {
typedef int (*pfunc32)(int);
typedef int (*pfunc64)(__int64);
pfunc32 call_func;
if (b64)
call_func = func64; //error C2440: '=' : cannot convert from 'int (__cdecl *)(__int64)' to 'pfunc32'
else
call_func = func32;
//...
call_func(6);
}
How can I avoid this error and cast call_func to pfunc32 or pfunc64?
The language requires all functions called through the same function pointer to have the same prototype.
Depending on what you want to achieve, you could use the pointer/cast aproach already mentioned (which satisfies this requirement at the loss of type safety) or pass a union instead:
union u32_64
{
__int64 i64;
int i32;
};
int func64(union u32_64 a) {
return (int) a.i64/2;
}
int func32(union u32_64 a) {
return --a.i32;
}
void do_func(bool b64) {
typedef int (*pfunc)(union u32_64);
pfunc call_func;
if (b64)
call_func = func64;
else
call_func = func32;
//...
union u32_64 u = { .i64 = 6 };
call_func(u);
}
Pass a void pointer and cast it in the function body.
Of course this means less compiler control if you use the wrong type; if you call func64 and pass an int to it the program will compile and produce wrong results without giving you any tip of what is going wrong.
int func64(void *a) {
__int64 b = *((__int64*) a);
return (int) b/2;
}
int func32(void *a) {
int b = *((int *) a)
return b-1;
}
I need to call func32() or func64() depending on flag b64
So do that:
void do_func(bool b64) {
if (b64)
func64(6);
else
func32(6);
}
Well, first of all, please note that function func32 is returning the input argument as is.
This is because with return a--, you are returning the value of a before decrementing it.
Perhaps you meant to return a-1 instead?
In any case, you can simply declare this function as int func32(__int64 a).
This way, it will have the same prototype as function func64, but will work exactly as before.
BTW, calling a function through a pointer might be more "expensive" than a simple branch operation, so depending on your application, you might be better off with a simple if/else conditional statement...
Make a wrapper for func64:
int func64_as_32(int a) {
return func64(a);
}
Now you can assign either func32 or func64_as_32 to call_func since they have the same signature. The value you pass in, 6, has type int so passing it to func64_as_32 has the same effect as passing it directly to func64.
If you have call sites where you pass in a value of type __int64 then you'd do it the other way around, wrap func32.
As bool in C++ converts to int ( true => 1, false => 0 ) you can use b64 as array index. So take SJuan76's advice, convert your functions prototype to int f(void*) and put them into array int (*array_fun[2])(void* x); . You can call these functions then like that :
int p = 6;
array_fun[b64](&p);
When I define a function of a class, I call another function of the same class within it. But when I do not type the class name it gives segmentation fault. Check below.
Header file
class DomainSolver
{
int fnc1 (UserDefinedType & var);
int fnc2 (UserDefinedType & var);
};
C file
int DomainSolver::fnc2 (UserDefinedType & var)
{
return 0;
}
int DomainSolver::fnc1 (UserDefinedType & var)
{
// fnc2 (var); // does not work
DomainSolver::fnc2(var); // works
return 0;
}
Wild guess… since the code you presented does not have any issues…
The function being called is declared virtual in a base class, so even if the virtual keyword is not present in the declaration here it is virtual.
The function being called does not access any member of the object.
You are calling the function on an invalid pointer or reference (for example through a null pointer or on an object that has already been deleted.
If all those guesses are right, the use of the qualification inhibits the dynamic dispatch mechanism, avoiding the dereference of an invalid pointer to the vtable. The code is still wrong (due to the third point above), but it seems to work.
The solution is not to call a member function through an invalid pointer or reference.
Although as pointed out by Zac's reply, the functions as you present them are not properly formed, there shouldn't be a difference between calling the scoped version; if you are getting a segfault in one case and not the other it's possibly because of code elsewhere.
Here is an example that works just fine:
dsolver.hh
#ifndef DSOLVER_HH
#define DSOLVER_HH
class DomainSolver
{
public:
int fnc1 (int& var);
int fnc2 (int& var);
};
#endif
dsolver.cc
#include <iostream>
#include "dsolver.hh"
int DomainSolver::fnc1 (int& var)
{
std::cout << "fnc1\n";
fnc2( var );
var = -1;
return var;
}
int DomainSolver::fnc2 (int& var)
{
std::cout << "fnc2\n";
var = 100;
return var;
}
main.cc
#include <iostream>
#include "dsolver.hh"
int main()
{
DomainSolver my_dsolver;
int my_int = 5;
my_dsolver.fnc1(my_int);
return 0;
}
Assuming this is close to your actual code, you have undefined behavior in fnc1:
int DomainSolver::fnc1 (UserDefinedType & var)
{
// fnc2 (var); // does not work
DomainSolver::fnc2(var); // works
// missing return!!!
}
You declare it to return an int, but then never return anything (in either case). Both cases are UB, so anything they do is technically "valid", since your code is not.
This code should be:
int DomainSolver::fnc1 (UserDefinedType & var)
{
return fnc2 (var);
}
As a side note: This is a good example of why you should never ignore the warnings given by the compiler (as you should have received a warning with both versions).
EDIT
With your latest edit adding a return value to fnc1, you'll need to show more of your actual code as there is not enough there to properly diagnose the problem (with the return being there, there is nothing wrong with your shown code).
I'm using error codes for handling errors in my c++ project. The problem is how to return error codes from a function which is supposed to return some variable/object.
consider this:
long val = myobject.doSomething();
Here, myobject is an object of some class. If doSomething function encounters some error condition then how should it notify the caller (Without using exceptions).
Possible solutions:
Have a data member (say err_) in the class which can be checked by the caller. But it would be unsafe in a multi-threaded application sharing the same object and calling the same function.
Use some global error variable, again same issue in a multi-threaded environment.
Now how can I notify the caller about some error condition?
Make a template called, say, Maybe that it parametrized by your return value type. Whenever you return a value, wrap it in this template like this:
Maybe<long> result = object.somemethod();
The Maybe template would have a way of being instantiated with an error code (probably a static method):
return Maybe<long>::error(code);
But ordinarily would just be returned with the value:
Maybe<long> retval;
retval = 15;
return retval;
(You would have to, of course, override the appropriate constructors, assignment operators, etc.)
In the client side you call a method to check for the error.
Maybe<long> result = object.somemethod();
if (result.is_error)
{
... handle the error ...
}
else
{
... use the result ...
}
Again you'd need the appropriate operators defined to use Maybe<long> wherever there's a long required.
This sounds like a lot of work, but really the work is done once in making a good, bulletproof Maybe template. You'll also have to do some performance tuning on it to avoid nasty overheads. If you want to make it more flexible you can parametrize it on both the return value type and the error type. (This is only a minor increase in complexity.)
You probably want something like Alexandresu's Expected<T> idiom.
You can pass variable as reference and return error code in it.
You can return a std::pair holding both an error code (or error object) and the desired return object. The object of interest needs a default constructor or value so you can return something even when an error is encountered.
It is common to return a return/error code, and make available a property or member with the results.
int retCode = myobject.doSomething();
if (retCode < 0){ //Or whatever you error convention is
//Do error handling
}else{
long val = myobject.result;
}
It is also common to pass in a pointer that is set to the return value, and return the return/error code. (See HrQueryAllRows).
long val = INIT_VAL;
int retCode = myObject.doSomething(&val);
if (retCode < 0){
//Do error handling
}else{
//Do something with val...
}
You have three options:
Create a class containing the return value and a possible error code.
Use something like boost::optional for the return value, which allows
for invalid responses.
Pass a reference to a variable and return any possible error code
within that.
I see there are many nice solutions, but I approach it in another way if I have this situation.
auto doSomething()
{
// calculations
return std::make_pair(error_code, value)
}
int main()
{
auto result = doSomething();
if (!result.first)
{
std::cout << result.second;
}
else
{
std::cout << "Something went wrong: " << result.second;
}
}
For me it's a clean solution than passing bool as reference. auto return type deduction is supported from c++14
Return an error handle. Have an error manager keep the error codes and additional informations (e.g. ERROR_INVALID_PARAMETER and name-value-pairs like ParameterName="pszFileName"). This information can be accessed using the handle. The caller can check the error handle against a NO_ERROR_HANDLE. If true, no error occurred. The caller can augment the error information and pass the handle up the stack.
The error manager can be one for the process or one for each thread.
I would suggest following:
class foo {
public:
long doSomething();
long doSomething(error_code &e);
};
Where error_code is some type that holds error. It may be integer or better something based on boost::system::error_code.
And you supply two functions:
First version throws the error, for example throw boost::system::system_error that is created from boost::system::error_code.
Second returns the error code into e.
The most common practice is to return the error code
long result;
int error = some_obj.SomeMethod(&result);
or return a value that indicate there was an error:
long result = some_obj.SomeMethod();
if (result < 0) error = some_obj.GetError();
In C++17 you use std::optional from the <optional> header:
std::optional<long> myobject = some_func(some_bool);
if (myobject.has_value()) {
// do stuff with myobject.value()
} else {
// myobject has no value
}
// ...
// Example function that returns an optional
std::optional<long> some_func(bool b) {
if (b)
return 15;
return {};
}
define all the error codes in a File. based on error category you can return the error code and the caller can decide what went wrong and caller can return its own error code.
for example
#define FILE_ERROR 1
#define SANITY_ERROR 2
int WriteToFile(char* Data, int iErrorCode)
{
char* FileName;
if (!FileOpen(FileName, &iErrorCode))
{
//Analyze error code and make decision on what to ignore or terminate
iErrorCode = FILE_ERROR;
return 0;
}
}
int FileOpen(char* FileName, int* iErrorCode)
{
if (FileName == null)
{
iErrorCode = SANITY_ERROR;
return 0;
}
///// next code blocks
return 1;
}
I found a new way to do it. It is non-standard and this is an entirely new way to do it.
So consider using this approach cautiously.
Use the following header file:
SetError.h:
#include <string> // for string class
#ifndef SET_ERROR_IS_DEFINED
#define SET_ERROR_IS_DEFINED
class Error {
public:
int code = 0;
std::string errorMessage;
std::string fileName;
std::string functionName;
Error() {}
Error(int _errorCode, std::string _functionName = "", std::string _errorMessage = "", std::string _fileName = "")
{
code = _errorCode;
functionName = _functionName;
errorMessage = _errorMessage;
fileName = _fileName;
}
};
#if defined(_DEBUG) || !defined(NDEBUG)
#define ___try { _ERROR.code = 0; bool __valid_try_mode_declared;
#define ___success }
#define SetError(pErrorData) __valid_try_mode_declared = true; _ERROR = *pErrorData; delete pErrorData;
#else
#define ___try { _ERROR.code = 0;
#define ___success }
#define SetError(pErrorData) _ERROR = *pErrorData; delete pErrorData;
#endif
#endif
inline Error _ERROR;
Include it everyware.
Example of how to use:
Main.cpp:
#include "SetError.h"
#include <iostream>
bool SomeFunction(int value) ___try;
{
if (value < 0) {
SetError(new Error(10, "SomeFunction", "Some error", "File main.cpp"));
return false;
}
return true;
} ___success; // You mast to warp the function with both ___try and ___success
// These keywords must be at the start and the end of the function!
int main()
{
using namespace std;
bool output = SomeFunction(-1);
if (_ERROR.code != 0) { // This is how you check the error code. using the global _ERROR object
cout << "error code: " << _ERROR.code << ", from function: "
<< _ERROR.functionName << ", from file: " << _ERROR.fileName;
}
cout << endl << "Founction returned: " << output << endl;
return 1;
}
If you have some functions that run in another thread, these functions need to be inside namespace and then you can do this:
namespace FunctionsInSomeThread
{
#include "SetError.h"
bool SomeFunc1() ___try;
{
SetError(new Error(5, "SomeFunction2", "Some error from another thread", "File main.cpp"))
return true;
} ___success;
bool SomeFunc2() ___try;
{
SetError(new Error(5, "SomeFunction2", "Some error from another thread", "File main.cpp"))
return true;
} ___success;
}
And to access _Error, you need to add the namespace of the thread
if (FunctionsInSomeThread::_ERROR.code != 0)
{
// Error handling
}
Or in case it is inside the same namespace then no need to add FunctionsInSomeThread:: before.
The idea behind this is that you can't warp the function only with ___success; keyword. You will get compile error. So the developer will never return old error code from another function.
If you wrote ___success; at the end of the codeblock, you must write also ___try; at the start!
You also can't use SetError macro if it is not wrapped in ___try; and ___success;.
The idea come from the AutoIt language where you have this consept:
https://www.autoitscript.com/autoit3/docs/functions/SetError.htm
So this is almost the same in C if you use this header.