how to get compilation warnings like in printf inside class member function - c++

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.

Related

using a class type in printf()

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).

Why do these two pieces of code using constexpr, __PRETTY_FUNCTION__ and char * have different results?

I have this code where if you comment out the line commented "But this doesn't work?!" it compiles just fine, but if you don't, the compiler generates an error.
At least, gcc 8.2 generates an error.
But, they seem identical to me. What's the problem? Is this legal code at all?
template <int x>
struct test_template {
static int size() { return x; }
};
constexpr int ce_strlen(char const *s)
{
int i = 0;
while (s[i]) ++i;
return i;
}
int joe()
{
constexpr int plen = ce_strlen(__PRETTY_FUNCTION__); // This works
test_template<plen> a; // This declaration is valid.
test_template<ce_strlen(__PRETTY_FUNCTION__)> b; // But this doesn't work?!
return a.size() + b.size();
}
I ran into this while trying to come up with a way to create profile tags for an intrusive profiling system at compile time. I succeeded, but my final code does not involve using ce_strlen.
Indeed this is a bug in GCC as discussed in the comments, but I thought I'd throw in some additional insight as to the nature of this bug. In the GCC NEWS file there is this line:
__FUNCTION__ and __PRETTY_FUNCTION__ are now treated as variables by the parser; previously they were treated as string constants. So code like printf (__FUNCTION__ ": foo") must be rewritten to printf ("%s: foo", __FUNCTION__). This is necessary for templates.
But __PRETTY_FUNCTION__ isn't really a variable, it's a special case treated in the parser as we see in constexpr.c:
case DECL_EXPR:
{
tree decl = DECL_EXPR_DECL (body);
if (TREE_CODE (decl) == USING_DECL
/* Accept __func__, __FUNCTION__, and __PRETTY_FUNCTION__. */
|| DECL_ARTIFICIAL (decl))
return NULL_TREE;
return error_mark_node;
}
If it really was a variable, we'd expect it to pass the same test cases as these:
constexpr const char* s2 = "TEST";
constexpr const char* s3 = s2;
test_template<ce_strlen("TEST")> c;
test_template<ce_strlen(s2)> d;
test_template<ce_strlen(s3)> e;

How can I simplify the calling of this function?

I've written (and use) my own string formatting function and I'd like to simplify the usage of the function, in a specific way shown below, but I'm unsure how.
Here's the relevant code:
// Object that can hold a copy of every type I want to print.
// Stores the copy in a union, with an enumeration to identify
// the type. any uses C++ constructors, but could also be implemented
// with C99 designated initializers, like so: https://ideone.com/ElQgBV
struct any
{
...
}
// The string format function requires the variable arguments
// to all be of the 'any' type for type safety and (essential for
// my purposes) positional printing.
// Arguments are accessed with a va_list, so essentially
// the variable arguments are treated as an array of any objects.
char* format_function_(const char* fmt, ...);
// I call the above function with this macro that expands the
// variable arguments and adds a default-constructed sentinel
// at the end. The sentinel is used by the function to count
// how many arguments were passed.
#define format(fmt, ...) format_function_(fmt, __VA_ARGS__, any())
// Calling the function like so, via the above macro...
char* str = format("bits:%4b string:%1 %0 int:%3h float:%2.2\n",
any("world"), any("hello"), any(3.14159f), any(42), any((u8)(1<<4)));
// ...returns this string:
// bits:00010000 string:hello world int:0000002A float:3.14
I'd like to be able to call the function like regular *printf style functions...
char* str = format("bits:%4b string:%1 %0 int:%3h float:%2.2\n",
"world", "hello", 3.14159f, 42, (u8)(1<<4));
...with the use of the any object hidden away, possibly behind another macro.
How can I accomplish this?
Edit/Update The positional arguments are essential for my purposes. Any answer that does not preserve this functionality is not a valid answer.
Since the C++11 standard there's something called parameter packs which makes this very simple:
char* format_function(const char* fmt, ...)
{
...
}
template<typename ...T>
char* format(const char* fmt, T... values)
{
return format_function(fmt, any(values)...);
}
...
char* str = format("bits:%4b string:%1 %0 int:%3h float:%2.2\n",
"world", "hello", 3.14159f, 42, (u8)(1<<4));
Maybe you'ld like something like this? (Alert: C++11 code!)
#include <stdio.h>
inline void format() {}
void format(char ch) {
fputc(ch, stdout);
}
void format(int i) {
if(i < 0) {
fputc('-', stdout);
i = -i;
}
int divider = 1;
while(i / divider >= 10)
divider *= 10;
do {
int digit = i / divider;
i -= divider * digit;
divider /= 10;
fputc('0' + digit, stdout);
} while(divider > 0);
}
void format(const char *str) {
fputs(str, stdout);
}
// TODO: Add more 'format()' overloads here!
template<typename FirstArg, typename... OtherArgs>
inline void format(const FirstArg &first, OtherArgs... others) {
format(first);
format(others...);
}
Then, you can simply...
const char *glorifiedIndex(int index) {
switch(index % 10) {
case 1:
return "st";
case 2:
return "nd";
case 3:
return "rd";
default:
return "th";
}
}
int main(int argc, const char *const argv[]) {
format("Hello, world!\n");
format("My name is ", argv[0], ", and I was given ", argc - 1, " argument", argc != 2 ? "s" : "", ".\n\n");
for(int i = 1; i < argc; i++)
format(i, glorifiedIndex(i), " argument: \"", argv[i], "\"\n");
format("Goodbye, world!\n");
}
This is a more flexible and elegant model, for the following reasons:
Semantically safe.
Type safe.
No <cstdarg> stuff.
No any stuff.
No incredibly badly-designed iostream stuff.
It's too simple to implemet, and I mean too much :). Compare this few lines of code with a typical 3000+ lines long printf.c. The difference is in several orders of magnitude!
You may have nostalgic moments relating with Java and Python.
If you change the type of any expression for whatever reason (i.e, int to unsigned), the function accomodates itself to this.
(Both good and evil) compiler optimizations can kick in easily.
The user of the library may extended the abilities of the format() function by means of overloading it with user-defined types.
This imposibilites the use of dynamic formats (this is intended for obvious security reasons).
This forces you to create special functions for what I call bit-printing, i.e, printing in a machine-parsable way, rather than human-readable as format() did, does, and will do.
You may use overloading features to extend this list yourself :).

How to printf() a user class?

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.

C++11 Function That Only Accepts String Literals?

I want to write a C++11 function that will only accept string literals as a parameter:
void f(const char* s) { static_assert(s is a string literal); ... }
That is:
f("foo"); // OK
char c = ...;
f(&c); // ERROR: Doesn't compile
string s = ...;
f(s.c_str()); // ERROR: Doesn't compile
etc
Is there anyway to implement this? The signature of the function is open to changes, as is adding the use of macros or any other language feature.
If this is not possible what is the closest approximation? (Can user-defined literals help in anyway?)
If not is there a platform specific way in GCC 4.7 / Linux ?
I think the closest you are going to get is this
template<int N>
void f(const char (&str)[N]){
...
}
It will compile with literals and arrays but not pointers.
An alternative might be to make a GCC extension to check at compile time that your particular function is only called with a literal string.
You could use MELT to extend GCC. MELT is a high-level domain specific language to extend the GCC compiler, and is very well suited for the kind of check you want.
Basically, you would add a new pass inside GCC and code that pass in MELT which would find every gimple which is a call to your function and check that the argument is indeed a literal string. The ex06 example on melt-examples should inspire you. Then subscribe to gcc-melt#googlegroups.com and ask your MELT specific questions there.
Of course, this is not a foolproof approach: the function could be called indirectly thru pointers, and it could e.g. have a partial literal string, e.g. f("hello world I am here"+(i%4)) is conceptually a call with some literal string (e.g. in .rodata segment), but not in the generated code nor in the gimple.
I use this :
// these are used to force constant, literal strings in sqfish binding names
// which allows to store/copy just the pointer without having to manage
// allocations and memory copies
struct _literalstring
{
// these functions are just for easy usage... not needed
// the struct can be empty
bool equal(_literalstring const *other) { return !strcmp((const char *)this, (const char *)other); }
bool equal(const char *other) { return !strcmp((const char *)this, other); }
const char *str(void) { return (const char *)this; }
bool empty(void) { return *(const char *)this == 0; }
};
typedef _literalstring *LITSTR;
constexpr LITSTR operator "" _LIT(const char *s, size_t) {
return (LITSTR)s;
}
Then you just declare your function like this :
void myFunc(LITSTR str)
{
printf("%s\n", str->str());
printf("%s\n", (const char *)str);
const char *aVar = str->str();
const char *another = (const char *)str;
}
And you call it like this:
myFunc("some text"_LIT);
If you do something like this:
myFunc("some text");
myFunc(aTextVariable);
you get a compiler error.