Fwd: No sscanf Expected Type Warnings When Used Through A Template

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Fresh start on a Monday morning and I can see how to setup the #define to avoid the use of __VA_ARGS__ in my main code.

#include <stdarg.h>
#include <stdio.h>

bool message_scanner(const char *message, const char *format, ...)
__attribute__((format(__scanf__,2,3)));

// Cannot use __attribute__ format on variadic function templates
//template<class...Ts>
//bool the_message_scanner(const char *message, const char *format, Ts const&...ts)
// __attribute__((format(__scanf__,2,3)));

template<class...Ts>
bool the_message_scanner(const char *message, const char *format, Ts const&...ts)
{
size_t num_scanned(sscanf(message, format, ts...));
bool got_them_all(num_scanned == sizeof...(ts));
return got_them_all;
}

bool message_scanner(const char *message, const char *format, ...)
{
va_list args;
bool state(false);

va_start(args,format);
state = the_message_scanner(message, format, args);
va_end(args);

return state;
}

#define FMT_SCANNER(...) \
(false) ? message_scanner(__VA_ARGS__) : the_message_scanner(...)

int main ()
{
bool correct(false);
short int anInt(0);
char aChar('c');
float aFloat(0.0);

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wwrite-strings"
char* message = "EXAMPLE001:01,02";
#pragma GCC diagnostic pop

// Warnings are given about expected argument types
if(FMT_SCANNER(message, "<EXAMPLE%x:%x,%i", &anInt, &aChar, &aFloat))
{
correct = true;
}

// Warnings are given about expected argument types
if(2==sscanf(message, "<EXAMPLE%x:%x,%i", &anInt, &aChar, &aFloat))
{
correct = true;
}

return correct?0:1;
}


I am happy with that even if the warning messages are a little odd with the extra layer of abstraction. e.g.
$ gcc -std=c++11 sscanf_template_warnings_example_with__attribute__and_tri.cpp
sscanf_template_warnings_example_with__attribute__and_tri.cpp: In function ‘int main()’:
sscanf_template_warnings_example_with__attribute__and_tri.cpp:33:40: warning: format ‘%x’ expects argument of type ‘unsigned int*’, but argument 3 has type ‘short int*’ [-Wformat=]
(false) ? message_scanner(__VA_ARGS__) : the_message_scanner(...)
^
sscanf_template_warnings_example_with__attribute__and_tri.cpp:48:6: note: in expansion of macro ‘FMT_SCANNER’
if(FMT_SCANNER(message, "<EXAMPLE%x:%x,%i", &anInt, &aChar, &aFloat))


Once again, thank you for your assistance.

On Fri, 13 Nov 2015 at 12:40 Thomas Thorne <tafthorne@xxxxxxxxx> wrote:

Thank you that is a helpful pointer to get me on my way.

> You should be able to solve the problem by adding
> __attribute__((format(scanf, blah blah))) to your template function,
> which tells the compiler it requires a string literal that meets the
> scanf format rules. Then calls to your own sccanf wrapper can be
> checked (assuming you pass a string literal to the wrapper).

I don't think I can use the format attribute on a variadic function
template. When I try to do so I get an error stating:
sscanf_template_warnings_example_with__attribute__.cpp:12:6: error: args to be formatted is not ‘...’
bool the_message_scanner(const char *message, const char *format, Ts const&...ts)

I do not see that limitation mentioned in the document you have pointed
to so perhaps I am just trying to use the system incorrectly. The
limitation was mentioned on
http://zverovich.net/2015/04/22/compile-time-checking-of-printf-args-in-cppformat.html which provides some helpful suggestions about using a macro in some cases. The best I could come up with so far is the following:

#include <stdarg.h>
#include <stdio.h>

bool message_scanner(const char *message, const char *format, ...)
__attribute__((format(__scanf__,2,3)));

// Cannot use __attribute__ format on variadic function templates
//template<class...Ts>
//bool the_message_scanner(const char *message, const char *format, Ts const&...ts)
// __attribute__((format(__scanf__,2,3)));

template<class...Ts>
bool the_message_scanner(const char *message, const char *format, Ts const&...ts)
{
size_t num_scanned(sscanf(message, format, ts...));
bool got_them_all(num_scanned == sizeof...(ts));
return got_them_all;
}

bool message_scanner(const char *message, const char *format, ...)
{
va_list args;
bool state(false);

va_start(args,format);
state = the_message_scanner(message, format, args);
va_end(args);

return state;
}

int main ()
{
bool correct(false);
short int anInt(0);
char aChar('c');
float aFloat(0.0);

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wwrite-strings"
char* message = "EXAMPLE001:01,02";
#pragma GCC diagnostic pop

// Warnings are given about expected argument types
if(message_scanner(message, "<EXAMPLE%x:%x,%i", &anInt, &aChar, &aFloat))
{
correct = true;
}

// Warnings are given about expected argument types
if(2==sscanf(message, "<EXAMPLE%x:%x,%i", &anInt, &aChar, &aFloat))
{
correct = true;
}

return correct?0:1;
}


The indirection through a function that uses __VA_ARGS__ seems a little
inelegant but it is possible this is the best that can be done when
mashing together some C and C++ behaviour. I would have liked to use
something like stringstrem but there isn't any steam support on my
target system.

If anyone else has any other comments or suggestions about the code I
have come up with I would be grateful to hear them. I am pleased to
have an alternative to commenting in and out sscanf equivalent lines.

--
Thomas Thorne <tafthorne@xxxxxxxxxxxxxx>

-----Original Message-----
From: Jonathan Wakely <jwakely.gcc@xxxxxxxxx>
To: TafThorne@xxxxxxxxxxxxxx
CC: gcc-help <gcc-help@xxxxxxxxxxx>
Subject: Re: No sscanf Expected Type Warnings When Used Through A
Template
Date: Fri, 13 Nov 2015 09:59:08 +0000

On 13 November 2015 at 09:31, Thomas Thorne <tafthorne@xxxxxxxxx> wrote:
> Good Morning,
>
> I have come across something that I feel a shortcoming in the warnings
> that gcc issues when compiling some C++ code. Calling it a bug seems a
> bit harsh so I thought I would ask this mailing list of their opinion
> before raising an issue. When I use a template to perform some sscanf
> work on a string I loose some of the -Wformat warnings about the
> expected argument types.
>
> Here is a set of C++ code that demonstrates the warnings occurring for
> sscanf and not happening for the template.

This has nothing to do with templates, you get exactly the same
behaviour (i.e. no warnings) if you replace the function template
with:

bool message_scanner(const char *message, const char *format, short
int* i, char* c, float* f)
{
size_t num_scanned(sscanf(message,format,i, c, f));
bool got_them_all(num_scanned == 3);
return got_them_all;
}

The problem is simply that the compiler can't check the call to sscanf
unless the first argument is a string literal.

You should be able to solve the problem by adding
__attribute__((format(scanf, blah blah))) to your template function,
which tells the compiler it requires a string literal that meets the
scanf format rules. Then calls to your own sccanf wrapper can be
checked (assuming you pass a string literal to the wrapper).

The format attribute is documented at
https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html

Attachment: signature.asc
Description: GooPG digital signature


[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux