__attribute__ format for specific specifiers? - gcc

I would like to give the users of my API the possibility to pass a custom format string.
Now, I know what kind of specifiers I am expecting (for a single double), and I would like to make clang aware of this.
The clang documentation (which actually just points to the gcc documentation) makes it seem as if I could only specify the format in terms of actual parameters to my function/method.
However, I would just like to tell clang: "If it contains one, and only one %f specifier (with whatever flags, width or precision the caller would like), it's OK"
I can't seem to find that information. Any pointers?
Thanks

Looking at the gcc documentation, I don't think there's a way to directly do what you want.
(I'm assuming that your goal is to require a format suitable for printing a single float.)
The closest thing I can think of, is if you have your function void myfunc(const char *fmt)
you could rewrite it as
extern void do_myfunc(const char *fmt); /* the real body of myfunc() */
inline void myfunc(const char *fmt) { /* put this in the header */
if (0) {
float f = 0.0f;
printf(fmt, f);
}
do_myfunc(fmt);
}
and rely on clang to remove the dead code. Of course, clang might complain about said dead code, then...

Related

Feeding boost::format with variadic parameters

I am attempting to write a logging function which takes a variadic argument list and prints in a safe manor.
vprintf seems like the obvious answer, but I cannot seem to find a safe way to handle when the format string expects more arguments than were provided.
Additionally, it would be very nice if I could rearrange the order the parameters are printed.
This second requirement led me to boost::format, which seems to be exactly what I want, except that it does not accept a va_list for input.
I have done some extensive searching and the closest I could get was this solution:
boost::format with variadic template arguments
Unfortunately I am restricted to a specific gcc version which does not seem to include the std::initializer_list
In my searching, I have stumbled upon boost::preprocessor which seems like it should be able to accomplish what I want, but I am struggling with the implementation of it.
So, ideally, what I'm searching for is something that works as follows:
void loggerFunc(const char* msgFormat, ...){
boost::format f(msgFormat);
va_list args;
va_start(args, msg);
f & MagicalFunctionCall(args);
va_end(args);
}
Where this MagicalFunctionCall(args) would convert my args, for example:
1, "Test", 3.4, "OtherString"
into something like:
1 & "Test" & 3.4 & "OtherString"
I'm not necessarily tied to boost::preprocessor or anything boost really, but it would be ideal to accomplish this without pulling in any additional 3rd party dependencies (we already use boost elsewhere in the project). I just suggested those libraries, because they seemed to be the most promising in accomplishing all of the above.
Thanks!
Instead of Boost Format you could use the fmt library which supports older compilers ({fmt} 4 supports gcc 4.4):
void loggerFunc(const char *format, fmt::ArgList args) {
std::string s = fmt::format(format, args);
// log s
}
FMT_VARIADIC(void, loggerFunc, const char *)
The loggerFunc generated by FMT_VARIADIC can be used with variable number of arguments:
loggerFunc("{} {} {} {}", 1, "Test", 3.4, "OtherString");
Disclaimer: I'm the author of the fmt library.

Compile c code with float instead of double

I have a lengthy numeric integration scheme written in C. I'd like to test my algorithm in floating point precision. Is there a way to tell gcc to demote every occurrence of double to float in the entire program?
You can't safely do this without modifying your source code, but that shouldn't be terribly difficult to do.
Using the preprocessor to force the keyword double in your program to be treated as float is a bad idea; it will make your program difficult to read, and if you happen to use long double anywhere it would be treated as long float, which is a syntax error.
As stix's answer suggests, you can add a typedef, either at the top of your program (if it's a single source file) or in some header that's #includeed by all the relevant source files:
typedef double real; /* or pick a different name */
Then go through your source code and change each occurrence of double to real. (Be careful about doing a blind global search-and-replace.)
Make sure that the program still compiles, runs, and behaves the same way after this change. Then you can change the typedef to:
typedef float real;
and recompile to use float rather than double.
It's not quite that simple, though. If you're using functions declared in <math.h>, you'll want to use the right function for whatever floating-point type you're using; for example, sqrt() is for double, sqrtf() is for float, and sqrtl() is for long double.
If your compiler supports it, you might use the <tgmath.h> header, which defines type-generic macros corresponding to the math functions from <math.h>. If you use <tgmath.h>, then sqrt(x) will resolve to call the correct square root function depending on the type of the argument.
typedef double float;
Before any doubles that you want to replace should work, however be warned it may confuse some external libraries.
In the future, the best approach is to define your own float type:
#ifdef USE_FLOATS
typedef float MyFloatType;
#else
typedef double MyFloatType;
#endif
Or use templates, which has the added benefit of allowing you to change the code at runtime to use one or the other.

How can I get more information from clang substitution-failure errors?

I have the following std::begin wrappers around Eigen3 matrices:
namespace std {
template<class T, int nd> auto begin(Eigen::Matrix<T,nd,1>& v)
-> decltype(v.data()) { return v.data(); }
}
Substitution fails, and I get a compiler error (error: no matching function for call to 'begin'). For this overload, clang outputs the following:
.../file:line:char note: candidate template ignored:
substitution failure [with T = double, nd = 4]
template<class T, int nd> auto begin(Eigen::Matrix<T,nd,1>& v)
^
I want this overload to be selected. I am expecting the types to be double and int, i.e. they are deduced as I want them to be deduced (and hopefully correctly). By looking at the function, I don't see anything that can actually fail.
Every now and then I get similar errors. Here, clang tells me: substitution failure, I'm not putting this function into the overload resolution set. However, this does not help me debugging at all. Why did substitution failed? What exactly couldn't be substituted where? The only thing obvious to me is that the compiler knows, but it is deliberately not telling me :(
Is it possible to force clang to tell me what did exactly fail here?
This function is trivial and I'm having problems. In more complex functions, I guess things can only get worse. How do you go about debugging these kind of errors?
You can debug substitution failures by doing the substitution yourself into a cut'n'paste of the original template and seeing what errors the compiler spews for the fully specialized code. In this case:
namespace std {
auto begin(Eigen::Matrix<double,4,1>& v)
-> decltype(v.data()) {
typedef double T; // Not necessary in this example,
const int nd = 4; // but define the parameters in general.
return v.data();
}
}
Well this has been reported as a bug in clang. Unfortunately, the clang devs still don't know the best way to fix it. Until then, you can use gcc which will report the backtrace, or you can apply this patch to clang 3.4. The patch is a quick hack that will turn substitution failures into errors.

G++ error: ‘<anonymous>’ has incomplete type

I am forced to use a third party dongle access library that provides an include file 'sense4.h' with code as follows:
#if !defined _WINDOWS_
#define WINAPI
#define CONST const
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned int UINT;
typedef unsigned long ULONG;
typedef char CHAR;
typedef char TCHAR;
typedef void VOID;
...
#endif /* !defined _WINDOWS */
...
unsigned long WINAPI S4Startup(
VOID
);
unsigned long WINAPI S4Cleanup(
VOID
);
...
The problem is that g++ 4.6.1 complains about lines of code where typedefed VOID is used:
sense4.h:375:9: error: ‘<anonymous>’ has incomplete type
sense4.h:376:1: error: invalid use of ‘VOID {aka void}’
sense4.h:383:9: error: ‘<anonymous>’ has incomplete type
sense4.h:384:1: error: invalid use of ‘VOID {aka void}’
Is there anything I can do without changing the 'sense.h' include file to make my project compile with g++?
Update 1
I found out that the section 18 of C++ Standard Core Language Closed Issues, Revision 30 states:
If the parameter-declaration-clause is empty, the function takes no arguments. The parameter list (void) is equivalent to the empty parameter list.
Can a typedef to void be used instead of the type void in the parameter list?
Rationale: The IS is already clear that this is not allowed.
Quick summary: The code is not valid C++, though there's some lack of clarity about whether it should be. Using void rather than VOID, or just using empty parentheses, will avoid the error.
I think this is a bug in g++.
I thought this was a bug in g++. I'm now convinced that it isn't, though I argue that it would be better to make this a warning rather than a fatal error.
Normally in C++, a function with no parameters is declared with empty parentheses:
int foo();
As a concession to C compatibility, C++ also allows a C-style prototype, using void to indicate that the function has no parameters (since empty parentheses mean something else in C):
int bar(void);
g++'s interpretation seems to be that the void in this syntax here doesn't refer to the incomplete type void; rather, it treats it as a special syntax with a distinct use of the keyword.
I think you'll need to modify the header file to get g++ to accept it.
gcc accepts it as valid C, but that's not helpful if you need to #include it from a C++ source file -- unless you write a C wrapper and invoke it from your C++ code, which might be an acceptable workaround.
(Incidentally, I hate typedefs like that. What's the purpose of typedef void VOID;? Did the author think void was too confusing? I suspect it's for compatibility with very old C compilers that didn't support the void keyword, but the need for that is long past.)
Here's the relevant description from the latest draft of the ISO C++ 2011 standard (8.3.5 [dcl.fct]):
The parameter-declaration-clause determines the arguments that can
be specified, and their processing, when the function is called. [ ...
] If the parameter-declaration-clause is empty, the function takes
no arguments. The parameter list (void) is equivalent to the empty
parameter list. Except for this special case, void shall not be a
parameter type (though types derived from void, such as void*,
can).
This implies that the void keyword in int bar(void); does refer to the type void. Since a typedef name is a synonym for the named type, int bar(VOID); should be equally legal. It would make the most sense for a typedef name like VOID to be accepted in place of void, but the wording of the standard actually refers to the keyword void, not to the type.
The whole purpose of permitting (void) is C compatibility. Just to add to the confusion, the 1990 ISO C standard requires the void keyword; the 1999 and 2011 C standards changed the wording, allowing a typedef instead. The response to C++ Defect Report #577 confirms that the current wording requires the void keyword, and proposes a change that will permit a typedef -- but that change is not yet in any ISO C++ standard. It will probably appear in the first Technical Corrigendum for C++ 2011, whenever it's published.
Thanks to another.anon.coward for finding the existing gcc bug report. I've added an overly verbose comment suggesting that the code is valid and the error message should not be produced -- and a later comment conceding that the code is invalid, but that a warning would be more appropriate than a fatal error.
In the meantime, I suggest contacting the provider of this sense4.h header file. If they intended it to #included only from C code, there's no real problem with it (other than the IMHO poor style); otherwise, they might consider using #ifdef __cplusplus, declaring the functions with (void) in C and with () in C++. And you could go ahead and make that change yourself. Whether g++ should accept the code or not, with a few changes it would be valid C, valid C++, acceptable to both gcc and g++, and better style.
If you've read this far and you're still awake, I'm impressed.

How to get warnings of incorrect string formatting (C++)

apologies in advance if i use poor terminology.
when i compile a C++ app under gdb and use printf() it gives me awesome warnings relating to the consistency of the format string and the arguments passed in.
eg, this code:
printf("%s %s", "foo");
results in a compiler warning "too few arguments for format", which is super-useful.
it will also give warnings about format string type vs. argument type.
it must have inspected the format string and compared that against the supplied argument types.
- is this sort of compile-time introspection something which can be added to ordinary source code, or is it something which needs to be compiled into gcc itself ?
fwiw this is under gcc 4.2.1 on os x.
You can do stuff like this for your own printf-like functions (as well as for scanf/strftime/strfmon-like functions):
#define PRINTF_FORMAT_CHECK(format_index, args_index) __attribute__ ((__format__(printf, format_index, args_index)))
void my_printf(const char *fmt, ...) PRINTF_FORMAT_CHECK(1, 2);
See the gcc manual for further details.

Resources