I have an error reporting functionality in my little C library I'm writing. I want to provide an errorf function in addition to the plain error function to allow embedding information in error messages easily.
/*
* Prints a formatted error message. Use it as you would use 'printf'. See the
* 'sio_error' function.
*/
void sio_errorf(const char *format, ...) {
// Print the error prefix
if (g_input == STDIN) fputs("error: ", stderr);
else fprintf(stderr, "%s: ", g_progname);
// Pass on the varargs on to 'vfprintf'.
va_list arglist;
va_start(arglist, format);
// This may produce the following warning -- ignore it:
// warning: format string is not a string literal
vfprintf(stderr, format, arglist);
va_end(arglist);
fputc('\n', stderr);
}
The problem is, I get this warning (compiling with clang 4.0 with the -Weverything switch):
warning: format string is not a string literal
I understand why doing this would be bad. Is there any way I can get rid of this warning? Can I somehow enforce that the format argument sio_errorf be a string literal, so that the compiler knows that it always will be, and that I'm simply passing it on?
I know I can use -Wno-format-nonliteral, but only if other people are going to manually compile it too, they won't do that. I'd rather something in the source code that silences the warning.
Ideally I would still get the warning if the string I passed to sio_errorf actually isn't a literal, but I'm not sure if that's possible.
If you're using GCC or one of its relatives, try an attribute on the declaration:
void sio_errorf(const char *format, ...) __attribute__((format(printf, 1, 2)));
To add the attribute to a definition, you can use this:
__attribute__((format(printf, 1, 2)))
static void sio_errorf(const char *format, ...) {
....
Many compilers will allow you to set warning levels in one way or another. For example, gcc allows the control via -W flags on the command line when invoking the compiler.
Hopefully that's the compiler you're using since a program like this:
#include <stdio.h>
int main (void) {
char *s = "xyzzy\n";
printf (s);
return 0;
}
generates the exact message you describe (assuming you've enabled the warnings with -Wformat and -Wformat-nonliteral).
The particular command line argument you would be looking for is:
-Wno-format-nonliteral
which will prevent complaints about the use of non-literal strings in those functions.
However, you may be looking for something more fine-grained so it also allows you to specify the disposition of certain diagnostic messages on the fly within your code with pragmas:
#include <stdio.h>
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
int main (void) {
char *s = "xyzzy\n";
printf (s);
return 0;
}
#pragma GCC diagnostic warning "-Wformat-nonliteral"
If you compile that with -Wformat -Wformat-nonliteral, you won't see the warning, because you've told gcc to ignore that particular warning for the main function.
Later versions of gcc than the one I run have the following options:
#pragma GCC diagnostic push
#pragma GCC diagnostic pop
which will push and pop the state of the diagnostics. This gets around the problems in my code above where you might configure that warning as an error - my second pragma would change it into a warning.
The use of push/pop would allow restoration to its original disposition with something like:
#include <stdio.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
int main (void) {
char *s = "xyzzy\n";
printf (s);
return 0;
}
#pragma GCC diagnostic pop
Related
I get the following compiler error, even though there is no "do" expression in my code.
gcc -Wall -g -c main.c -lasound
In file included from /usr/include/alsa/asoundlib.h:49:0,
from main.c:2:
main.c: In function ‘main’:
main.c:8:5: error: expected expression before ‘do’
if(snd_pcm_hw_params_alloca(¶ms) < 0) {
^
main.c:6:30: warning: unused variable ‘params’ [-Wunused-variable]
snd_pcm_hw_params_t *params;
^~~~~~
Makefile:15: recipe for target 'main.o' failed
make: *** [main.o] Error 1
From the following minimal reproducible example:
#include <stdio.h>
#include <alsa/asoundlib.h>
int main(int argc, char **argv)
{
snd_pcm_hw_params_t *params;
if(snd_pcm_hw_params_alloca(¶ms) < 0) {
return 0;
}
exit(0);
}
I'm aware this is not a valid ALSA program. I'm also aware that it appears snd_pcm_hw_params_alloca() doesn't even return anything worthwhile to check for errors against? That's not relevant though, this should valid C code regardless, even if it abuses the API.
Where is the "do" expression? If I go to /usr/include/alsa/asoundlib.h and poke around there, I don't see anything obvious that would indicate a problem.
If I remove the conditional if test, and get:
#include <stdio.h>
#include <alsa/asoundlib.h>
int main(int argc, char **argv)
{
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca(¶ms);
exit(0);
}
This will compile with no errors.
What is this?
If I look in pcm.h, I see:
#define snd_pcm_hw_params_alloca(ptr) __snd_alloca(ptr, snd_pcm_hw_params)
int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **ptr);
void snd_pcm_hw_params_free(snd_pcm_hw_params_t *obj);
void snd_pcm_hw_params_copy(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src);
However, this doesn't tell me anything. Why does the compiler produce this error?
I'm also aware that it appears snd_pcm_hw_params_alloca() doesn't even return anything worthwhile to check for errors against? That's not relevant though, this should valid C code regardless, even if it abuses the API.
No, if snd_pcm_hw_params_alloca() does not have a value you cannot compare it against 0. For example, the following is also invalid:
void func(void) { }
void other(void) {
if (func() < 0) { // Error
}
}
In reality, snd_pcm_hw_params_alloca() is a macro, and it’s a wrapper for another macro, __snd_alloca. The do is there to make it behave more like a statement. You can only call it as a statement on its own line, or anywhere else where a do loop is legal.
snd_pcm_hw_params_alloca(¶ms);
You cannot check for errors because alloca() does not check for errors. If alloca() fails, it will just stomp on your stack, and bad things will happen. You can’t do anything about it, except not use alloca() (this is why you might hear advice to avoid alloca).
For an explanation of why the do loop is used, see: C multi-line macro: do/while(0) vs scope block
For more information about how alloca() works, see: Why is the use of alloca() not considered good practice?
Program:
#ifndef PRINTF_H
#define PRINTF_H
#include "my_put_char.h"
int my_printf(char *str, ...);
#endif
This is my Header file for my function.
#include <stdio.h>
#include "my_put_char.h"
void my_put_char(char c)
{
fwrite(&c, sizeof(char), 1, stdout);
}
This is my putchar implementation(my_put_char.c).
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "printf.h"
int my_printf(char *str, ...)
{
if(str == NULL)
return 0;
int i;
char a;
va_list print;
va_start(print,str);
for(i = 0; str[i] ; i++)
{
if(str[i] == '%')
{
i++;
switch(str[i])
{
case 'c':
a = va_arg(print, char);
my_put_char(a);
break;
}
}
}
va_end(print);
return 0;
}
At last, this is a part of my printf implementation.
I'm testing with %c to display a character.
When I do my_print("%c", 'd'); from main.c
it compiles and displays d.
But when I do my_print("%c", "hi"); , it still compiles and displays a number.
Question:
After(or before) writing a = va_arg(print, char); Is there a way to check whether my input is a different data type?
I'm trying to display an error if my input is a different data type.
I'm on this subject for 2 days and couldn't find any answer.
Thank you so much for your time!
when I do my_print("%c", "hi"); , it still compiles and displays a number
You've got some undefined behavior, so be scared. Your my_printf would call va_arg with an argument of the bad type (expected char promoted to int, got char*).
To explain what is happening you should dive into implementation details (look into the assembler code, e.g. with gcc -Wall -fverbose-asm -O -S; study your processor, its instruction set architecture, its application binary interface and calling conventions). You don't want to do that, it could take years and is not reproducible.
Read absolutely Lattner's blog on UB, right now!
Then download C11 specification n1570....
You could also, with gcc, use some function attributes. Don't forget to compile with all warnings and debug info (gcc -Wall -Wextra -g)
after writing a = va_arg(print, char); Is there a way to check whether my input is a different data type?
No, not really and not always. But the format function attribute could help. And you could also spend months customizing GCC with your own plugin or some GCC MELT extension (that is not worth your time). Be aware of the Halting Problem and Rice's Theorem (each makes static source code program analysis so challenging). Look also into source analyzing tools like Frama-C.
I'm implementing printf function
BTW studying the source code of existing free software implementations of the C standard library (such as GNU glibc and musl-libc) could be inspirational; they are based upon syscalls(2).
#include <stdio.h>
int main() {
int t;
scanf("%d", &t);
printf("%d", t);
return 0;
}
I compiled the above C code using ideone.com and the following warning popped up:
prog.c: In function ‘main’:
prog.c:5: warning: ignoring return value
of ‘scanf’, declared with attribute warn_unused_result
Can someone help me understand this warning?
The writer's of your libc have decided that the return value of scanf should not be ignored in most cases, so they have given it an attribute telling the compiler to give you a warning.
If the return value is truly not needed, then you are fine. However, it is usually best to check it to make sure you actually successfully read what you think you did.
In your case, the code could be written like this to avoid the warning (and some input errors):
#include <stdio.h>
int main() {
int t;
if (scanf("%d", &t) == 1) {
printf("%d", t);
} else {
printf("Failed to read integer.\n");
}
return 0;
}
The warning (rightly) indicates that it is a bad idea not to check the return value of scanf. The function scanf has been explicitly declared (via a gcc function attribute) to trigger this warning if you discard its return value.
If you really want to forget about this return value, while keeping the compiler (and your conscience) happy, you can cast the return value to void:
(void)scanf("%d",&t);
I tried your example with gcc (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3.
The warning is issued if and only if optimizing, e.g., with option -O2 or -O3.
Requesting all warnings (-Wall) doesn't matter.
The classic idiom of casting to void has no effect, it does not suppress the warning.
I can silence the warning by writing
if(scanf("%d",&t)){};
this works, but it's a bit obscure for my taste. Empty {} avoids yet another warning -Wempty-body
Do this:
int main() {
int t;
int unused __attribute__((unused));
unused = scanf("%d",&t);
printf("%d",t);
return 0;
}
After reading all answers and comments on this page I don't see these yet another options to avoid the warning:
When compiling with gcc you can add to your command line:
gcc -Wall -Wextra -Wno-unused-result proc.c -o prog.x
Another option is to use -O0 as "optimization level zero" ignores the warning.
Using cast to (void) is simply useless when compiling with gcc
If debugging your code, you can always use assert() as in the example bellow:
u = scanf("%d", &t);
assert(u == 1);
But now, if you turn off assert via #define NDEBUG you will get a -Wunused-but-set-variable. You can then turn off this second warning by one of two ways:
Adding -Wno-unused-but-set-variable to your gcc command line, or
Declaring the variable with attribute: int u __attribute__((unused));
As pointed out in other answer, the second option unfortunately is not very portable, although it seems the best option.
At last, the defined MACRO bellow can help you if you are sure you want to ignore the return of a given function, but you are not comfortable turning off the warnings for all unused returns of functions:
#define igr(x) {__typeof__(x) __attribute__((unused)) d=(x);}
double __attribute__ ((warn_unused_result)) fa(void) {return 2.2;}
igr(fa());
See also this answer
One way to solve this is the IGUR() function as seen below. Extremely ugly, but nevertheless somewhat portable. (For old compilers which do not understand inline just #define inline /*nothing*/, as usual.)
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
inline void IGUR() {} /* Ignore GCC Unused Result */
void IGUR(); /* see https://stackoverflow.com/a/16245669/490291 */
int
main(int argc, char **argv)
{
char buf[10*BUFSIZ];
int got, fl, have;
fl = fcntl(0, F_GETFL);
fcntl(0, F_SETFL, fl|O_NONBLOCK);
have = 0;
while ((got=read(0, buf, sizeof buf))>0)
{
IGUR(write(1, buf, got));
have = 1;
}
fcntl(0, F_SETFL, fl);
return have;
}
BTW this example, nonblockingly, copies from stdin to stdout until all waiting input was read, returning true (0) if nothing was there, else false (1). (It prevents the 1s delay in something like while read -t1 away; do :; done in bash.)
Compiles without warning under -Wall (Debian Jessie).
Edit: IGUR() needs to be defined without inline, too, such that it becomes available for the linker. Else with cc -O0 it might fail. See: https://stackoverflow.com/a/16245669/490291
Edit2: Newer gcc require inline to be before void.
Actually it depends on what you need, if you just want to disable the warning of compiler, you can just ignore the return value of the function by the force conversion or you can just handle it, the meaning of the scanf function is the count of user input.
==== update ====
You can use
(void) scanf("%d",&t);
to ignore the return value of scanf
Can someone help me understand this warning?
No, but here is my contribution to the horror of warning suppression. To actively throw the return value out the window, elegance dictates wrapping our statement in a comprehensible lambda function, like this:
[&]{ return scanf("%d", &t); }();
My apologies.
scanf, printf is functions that returns value, usually in those kind of functions it's the amount of characters read or written. if an error occurs, you can catch the error also with the return code.
A good programming practice will be to look at the return value, however, I never saw someone who looks at the printf return value...
If you want the warning to disappear, you can probably change the severity of the compiler.
Since functions without arguments are valid in C, you can do the following:
#include <stdio.h>
static inline void ignore_ret() {}
int main() {
int t;
ignore_ret(scanf("%d", &t));
return 0;
}
just use a surrunding if () and an empty block, the terminating semikolon has to be in the next line (to prevent additional warnings)
#include <stdio.h>
main (int argc, char const *argv[]) {
...
if ( scanf("%d",&n) )
;
...
return 0;
}
I'm trying to intercept calls to printf using ld's -wrap option. I have the two files:
main.c:
#include <stdio.h>
int main(void) {
printf("printing\n");
printf("printing");
}
printf_wrapper.c:
int __real_printf(const char *format, ...);
int __wrap_printf(const char *format, ...) {
(void)format;
return __real_printf("WRAPPED\n");
}
And I compile with the following command:
gcc -Wl,-wrap,printf *.c
When I run the resulting a.out binary, I get this output:
printing
WRAPPED
Why does the wrapping fail if there's a newline in the string? I checked my system's stdio.h and printf isn't a macro. This is with gcc 5.3.0
Use the -fno-builtin option to tell gcc not to mess around with some specified functions. So, if you added -fno-builtin-printf it should work. In general it may cause some problems that would have been caught by the compiler to be missed. See the gcc docs for details, e.g. https://gcc.gnu.org/onlinedocs/gcc-4.2.2/gcc/C-Dialect-Options.html
#include <stdio.h>
int main() {
int t;
scanf("%d", &t);
printf("%d", t);
return 0;
}
I compiled the above C code using ideone.com and the following warning popped up:
prog.c: In function ‘main’:
prog.c:5: warning: ignoring return value
of ‘scanf’, declared with attribute warn_unused_result
Can someone help me understand this warning?
The writer's of your libc have decided that the return value of scanf should not be ignored in most cases, so they have given it an attribute telling the compiler to give you a warning.
If the return value is truly not needed, then you are fine. However, it is usually best to check it to make sure you actually successfully read what you think you did.
In your case, the code could be written like this to avoid the warning (and some input errors):
#include <stdio.h>
int main() {
int t;
if (scanf("%d", &t) == 1) {
printf("%d", t);
} else {
printf("Failed to read integer.\n");
}
return 0;
}
The warning (rightly) indicates that it is a bad idea not to check the return value of scanf. The function scanf has been explicitly declared (via a gcc function attribute) to trigger this warning if you discard its return value.
If you really want to forget about this return value, while keeping the compiler (and your conscience) happy, you can cast the return value to void:
(void)scanf("%d",&t);
I tried your example with gcc (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3.
The warning is issued if and only if optimizing, e.g., with option -O2 or -O3.
Requesting all warnings (-Wall) doesn't matter.
The classic idiom of casting to void has no effect, it does not suppress the warning.
I can silence the warning by writing
if(scanf("%d",&t)){};
this works, but it's a bit obscure for my taste. Empty {} avoids yet another warning -Wempty-body
Do this:
int main() {
int t;
int unused __attribute__((unused));
unused = scanf("%d",&t);
printf("%d",t);
return 0;
}
After reading all answers and comments on this page I don't see these yet another options to avoid the warning:
When compiling with gcc you can add to your command line:
gcc -Wall -Wextra -Wno-unused-result proc.c -o prog.x
Another option is to use -O0 as "optimization level zero" ignores the warning.
Using cast to (void) is simply useless when compiling with gcc
If debugging your code, you can always use assert() as in the example bellow:
u = scanf("%d", &t);
assert(u == 1);
But now, if you turn off assert via #define NDEBUG you will get a -Wunused-but-set-variable. You can then turn off this second warning by one of two ways:
Adding -Wno-unused-but-set-variable to your gcc command line, or
Declaring the variable with attribute: int u __attribute__((unused));
As pointed out in other answer, the second option unfortunately is not very portable, although it seems the best option.
At last, the defined MACRO bellow can help you if you are sure you want to ignore the return of a given function, but you are not comfortable turning off the warnings for all unused returns of functions:
#define igr(x) {__typeof__(x) __attribute__((unused)) d=(x);}
double __attribute__ ((warn_unused_result)) fa(void) {return 2.2;}
igr(fa());
See also this answer
One way to solve this is the IGUR() function as seen below. Extremely ugly, but nevertheless somewhat portable. (For old compilers which do not understand inline just #define inline /*nothing*/, as usual.)
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
inline void IGUR() {} /* Ignore GCC Unused Result */
void IGUR(); /* see https://stackoverflow.com/a/16245669/490291 */
int
main(int argc, char **argv)
{
char buf[10*BUFSIZ];
int got, fl, have;
fl = fcntl(0, F_GETFL);
fcntl(0, F_SETFL, fl|O_NONBLOCK);
have = 0;
while ((got=read(0, buf, sizeof buf))>0)
{
IGUR(write(1, buf, got));
have = 1;
}
fcntl(0, F_SETFL, fl);
return have;
}
BTW this example, nonblockingly, copies from stdin to stdout until all waiting input was read, returning true (0) if nothing was there, else false (1). (It prevents the 1s delay in something like while read -t1 away; do :; done in bash.)
Compiles without warning under -Wall (Debian Jessie).
Edit: IGUR() needs to be defined without inline, too, such that it becomes available for the linker. Else with cc -O0 it might fail. See: https://stackoverflow.com/a/16245669/490291
Edit2: Newer gcc require inline to be before void.
Actually it depends on what you need, if you just want to disable the warning of compiler, you can just ignore the return value of the function by the force conversion or you can just handle it, the meaning of the scanf function is the count of user input.
==== update ====
You can use
(void) scanf("%d",&t);
to ignore the return value of scanf
Can someone help me understand this warning?
No, but here is my contribution to the horror of warning suppression. To actively throw the return value out the window, elegance dictates wrapping our statement in a comprehensible lambda function, like this:
[&]{ return scanf("%d", &t); }();
My apologies.
scanf, printf is functions that returns value, usually in those kind of functions it's the amount of characters read or written. if an error occurs, you can catch the error also with the return code.
A good programming practice will be to look at the return value, however, I never saw someone who looks at the printf return value...
If you want the warning to disappear, you can probably change the severity of the compiler.
Since functions without arguments are valid in C, you can do the following:
#include <stdio.h>
static inline void ignore_ret() {}
int main() {
int t;
ignore_ret(scanf("%d", &t));
return 0;
}
just use a surrunding if () and an empty block, the terminating semikolon has to be in the next line (to prevent additional warnings)
#include <stdio.h>
main (int argc, char const *argv[]) {
...
if ( scanf("%d",&n) )
;
...
return 0;
}