I'm using C language.
I know that every function has return value(except void function).
But C6031 warning message appears only in scanf function.
It doesn't appear in other functions like printf or hello (look below).
Why this Phenomenon happens?
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int hello(void) {
printf("Hello World!");
return 10;
}
int main(void) {
int i;
scanf("%d", &i);
hello();
return 0;
}
As #SteveSummit indicates in a comment, most C implementations have a mechanism to identify functions whose return value should not be ignored.
C itself (as defined by the C standard) has always allowed a caller to ignore the return value of a function. It even allows a function declared with a return value type to not return any value as long as all callers ignore the return value.
However, that permissiveness does not generally lead to good programming practice. In some cases, it is very likely that ignoring the return value of a function will lead to a bug. scanf is considered to be such a function, so the authors of standard libraries tend to mark scanf as requiring that the return value be used.
There is no standard way to mark a function as requiring use of their return values. In GCC and Clang, this is done using the attribute warn_unused_result:
int fn (int a) __attribute__ ((warn_unused_result));
(See the GCC documentation for the warn_unused_result function attribute and how to turn off the warning (not recommended): the `-Wno-unused-result.)
In MSVC, it's done with the _Check_return_ macro, found in sal.h:
#include <sal.h>
_Check_return_ int fn (int a);
(See the Visual Studio docs for error C6031 and this documenation on the Source Annotation Library (sal).)
There are good reasons not to ignore the return value of any library function which uses the return value to indicate failure, including many standard library functions which do input or output. Ignoring input or output failure can lead to problems, but the problems are more evident when ignoring input failure because that can lead to the use of uninitialised values, which in turn can lead to Undefined Behaviour. That is certainly the case for scanf: ignoring its return value means that your program will not respond correctly to malformed input, which is almost certainly a bug.
Ignoring the failure of output functions will sometimes mean that the user is not warned about failure to save persistent data. That can be serious, and it may well be that some action needs to be taken to save that data. But in other cases, the error simply means that the user didn't see some logging message and most likely will not see future logging messages either. This might not be considered important.
put scanf inside an if.
scanf returns the number of successfully input parameter.
if(scanf("%d", &i)) {};
Related
For some homework I have to write a calculator in C. I wanted to input some string with scanf and then access it. But when I access the first element I get a segmentation error.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(){
char input1[30];
scanf("%s",input1);
printf("%s",input1);
char current = input1[0];
int counter = 0;
while(current != '\0'){
if(isdigit(current) || current == '+' || current == '-' || current == '*' || current == '/'){
counter++;
current = input1[counter];
}else{
printf("invalid input\n");
exit(1);
}
}
return 0;
}
The printf in line 3 returns the string, but accessing it in line 4 returns a segmentation error (tested in gdb). Why?
There are a few potential causes, some of which have been mentioned in the comments (I won't cover those). It's hard to say which one (or more) is the cause of your problem, so I guess it makes sense to iterate them. However, you may notice that I cite some resources in the process... The information is out there, yet you're not stumbling across it until it's too late. Something needs to change with how you research, because this is slowing your progress down.
On input/output dynamics, just a quick note
printf("%s",input1);
Unless we include a trailing newline, this output may be delayed (or "buffered"), which may have the effect of confusing you about the root of your issues. As an alternative to using a trailing newline (which I'd prefer, personally) you could explicitly force partial lines to be written by invoking fflush(stdout) immediately after each of the relevant output operations, or use setbuf to disable buffering entirely. I think this is unlikely to be your problem, but it may mask your problem, so it's important to realise, when using printf to debug, it might be best to include a trailing newline...
On main entry points
The first potential culprit I see is here:
int main()
I don't know why our education system is still pushing these broken lessons. My only guess is the professors learnt many years back using the nowadays irrelevant Turbo C and don't want to stay up-to-date with tech. We can further reduce this to a simple testcase to work out if this is your segfault, but like I said, it's hard to say whether this is actually your problem...
int main() {
char input1[30];
memset(input1, '\x90', sizeof input1);
return 0; // this is redundant for `main` nowadays, btw
}
To explain what's going on here, I'll cite this page, which you probably ought to go and read (in its entirety) once you're done here:
A common misconception for C programmers, is to assume that a function prototyped as follows takes no arguments:
int foo();
In fact, this function is deemed to take an unknown number of arguments. Using the keyword void within the brackets is the correct way to tell the compiler that the function takes NO arguments.
Simply put, if the linker doesn't know/can't work out how many arguments are required for the entry point, there's probably gonna be some oddness to your callstack, and that's gonna occur at the beginning or end of your program.
On input errors, return values and uninitialised access
#include <assert.h>
#include <stdio.h>
#include <string.h>
int main(void) {
char input1[30];
memset(input1, '\x90', sizeof input1);
scanf("%s",input1); // this is sus a.f.
assert(memchr(input1, '\0', sizeof input1));
}
In my testcase, I actually wrote '\x90' to each byte in the array, to show that if the scanf call fails you may end up with an array that has no null terminator. If this is your problem, this assertion is likely to throw (as you can see from the ideone demo) when you run it, which indicates that your loop is likely accessing garbage beyond the bounds of input1. On this note I intended to demonstrate that we (mostly) cannot rely upon scanf and friends unless we also check their return values! There's a good chance your compiler is warning you about this one, so another lesson is uto pay close attention to warning messages, and strive to have none.
On argument expectations for standard library functions
For many standard library functions it may be possible to give input that is outside of the acceptable domain, and so causes instability. The most common form, which I also see in your program, exists in the form of possibly passing invalid values to <ctype.h> functions. In your case, you could change the declaration of current to be an unsigned char instead, but the usual idiom is to put the cast explicitly in the call (like isdigit((unsigned char) current)) so the rest of us can see you're not stuck in this common error, at least while you're learning C.
Please note at this point I'm thinking whichever resources you're using to learn aren't working, because you're stumbling into common traps... please try to find more reputable resources to learn from so you don't fall into more common traps and waste more time later on. If you're struggling, check out the C tag wiki...
I have the following program that causes a segmentation fault.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
printf("TEST");
for (int k=0; k<(strlen(argv[1])); k++)
{
if (!isalpha(argv[1])) {
printf("Enter only alphabets!");
return 1;
}
}
return 0;
}
I've figured out that it is this line that is causing the problem
if (!isalpha(argv[1])) {
and replacing argv[1] with argv[1][k] solves the problem.
However, I find it rather curious that the program results in a segmentation fault without even printing TEST. I also expect the isalpha function to incorrectly check if the lower byte of the char* pointer to argv[1], but this doesn't seem to be the case. I have code to check for the number of arguments but isn't shown here for brevity.
What's happening here?
In general it is rather pointless to discuss why undefined behaviour leads to this result or the other.
But maybe it doesn't harm to try to understand why something happens even if it is outside the spec.
There are implementation of isalpha which use a simple array to lookup all possible unsigned char values. In that case the value passed as parameter is used as index into the array.
While a real character is limited to 8 bits, an integer is not.
The function takes an int as parameter. This is to allow entering EOF as well which does not fit into unsigned char.
If you pass an address like 0x7239482342 into your function this is far beyond the end of the said array and when the CPU tries to read the entry with that index it falls off the rim of the world. ;)
Calling isalpha with such an address is the place where the compiler should raise some warning about converting a pointer to an integer. Which you probably ignore...
The library might contain code that checks for valid parameters but it might also just rely on the user not passing things that shall not be passed.
printf was not flushed
the implicit conversion from pointer to integer that ought to have generated at least compile-time diagnostics for constraint violation produced a number that was out of range for isalpha. isalpha being implemented as a look-up table means that your code accessed the table out of bounds, therefore undefined behaviour.
Why you didn't get diagnostics might be in one part because of how isalpha is implemented as a macro. On my computer with Glibc 2.27-3ubuntu1, isalpha is defined as
# define isalpha(c) __isctype((c), _ISalpha)
# define __isctype(c, type) \
((*__ctype_b_loc ())[(int) (c)] & (unsigned short int) type)
the macro contains an unfortunate cast to int in it, which will silence your error!
One reason why I am posting this answer after so many others is that you didn't fix the code, it still suffers from undefined behaviour given extended characters and char being signed (which happens to be generally the case on x86-32 and x86-64).
The correct argument to give to isalpha is (unsigned char)argv[1][k]! C11 7.4:
In all cases the argument is an int, the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF. If the argument has any other value, the behavior is undefined.
I find it rather curious that the program results in a segmentation fault without even printing TEST
printf doesn't print instantly, but it writes to a temporal buffer. End your string with \n if you want to flush it to actual output.
and replacing argv[1] with argv[1][k] solves the problem.
isalpha is intended to work with single characters.
First of all, a conforming compiler must give you a diagnostic message here. It is not allowed to implicitly convert from a pointer to the int parameter that isalpha expects. (It is a violation of the rules of simple assignment, 6.5.16.1.)
As for why "TEST" isn't printed, it could simply be because stdout isn't flushed. You could try adding fflush(stdout); after printf and see if this solves the issue. Alternatively add a line feed \n at the end of the string.
Otherwise, the compiler is free to re-order the execution of code as long as there are no side effects. That is, it is allowed to execute the whole loop before the printf("TEST");, as long as it prints TEST before it potentially prints "Enter only alphabets!". Such optimizations are probably not likely to happen here, but in other situations they can occur.
If int x=printf("test"); executes safely, without error in c because printf returns an int value (the length of data it has printed.) But what about if we are not storing that integer value:
printf("text");
Why don't we get an error from this?
Many functions in C return something. Whether the programmer decides to do anything with that value is up to them - and often ignoring the return code leads to bugs... But in the case of printf(), the return value is seldom useful. It is provided for to allow the following code:
int width;
width = printf("%d", value); // Find out how wide it was
while (width++<15) printf(" ");
width = printf("%s", name);
while (width++<30) printf(" ");
I'm not saying that's good code (there are other ways to do this too!), but it describes why a function could return a value that isn't used very often.
If the programmer does decide to ignore the return value, there isn't a compiler error - the value is merely forgotten. It's a bit like buying something, getting the receipt, and dropping it on the floor - ignore the returned value.
The latest compilers can be instructed to flag code where returned values are ignored. But even these compilers can be taught which functions' returns are significant and which aren't. printf() would be in the second category.
You are not obliged to store the returned value, you can safely ignore it (as long as you're sure you really don't need it of course).
In most cases the value is simply stored in a CPU register. If you choose to ignore it, it will simply be lost once that register is overwritten.
This program:
#include <stdio.h>
#include <conio.h>
int main()
{
printf("%d %d %d",1) ;
getch();
return 0;
}
gives me result 1 0 0 instead of warning or error or 1
Could you please tell me the logic behind it ?
I'm using Visual Studio 2010 to compile this code.
This is undefined behavior and not something you should rely on. While using printf () if sufficient and appropriately matching arguments are not provided, like in your case printf("%d %d %d",1), C does not define what should happen in that case and so the behavior is not standard or defined.
It is possible that this could cause your program to crash (if the next memory addresses from where printf () read values are not accessible or non-existant).
With printf(), if insufficient matching arguments are not provided, the result is undefined behavior.
C does not define what should happen in this case.
... If there are insufficient arguments for the format, the behavior is
undefined. ... C11 ยง7.21.6.1 2
OP's code obviously printed 2 additional int with the value of 0. Why 0 today - look at the compiled assembly language. Might another compilation of the code has the same result - maybe - maybe not. It is not defined by the language.
printf doesn't care if there aren't enough arguments. "doesn't care" means that it doesn't actually check the number of items in the format list to make sure that a sufficient number of arguments have been specified.
if there are not enough arguments, printf will just access computer memory (the memory that would have been used, had sufficient arguments been specified) and use whatever data is there.
this is "undefined behavior" and the results will vary. it's possible that this could cause your program to crash (if the memory at the location is inaccessible or non-existent).
you'll find that this sort of thing is very common in languages like C, where you can do things should be considered "invalid" but that are simply accepted by the compiler.
If I have a program that is using scanf to get user inputted data:
scanf("%d",&val);
When I run it through lint I get warnings saying that scanf returns a int and it is not being assigned anywhere. What is the c practice to solve this problem? Do I type cast it as void?
(void)scanf("%d",&val);
The C best practice to solve this warnings is simple: Check the resultcode. The scanf function returns in the int if the operation has gone ok or not, and stores the error usually in errno.
The lack of resultcode checks usually results in big errors in certain situations.
The proper answer, of course, is to not ignore the return value. For a robust program, you should always (EDIT: usually) check that the return value indicates success, and fail gracefully when it does not.
Ideally you would do something like
int scanVal = scanf("%d", &val);
if (scanVal != 1) {
// wait a minute, scanf couldn't match input to a "%d"!
}
and then act on the output in a sensible manner.
Instead of silencing the lint message, just check the return value to make sure nothing has gone wrong. From the man page:
RETURN VALUE
These functions return the number of input items
successfully matched and assigned, which can be
fewer than provided for, or even zero in the event of an early
matching failure.
The value EOF is returned if the end of input is reached before
either the first successful conversion or a matching failure occurs. EOF is also >returned if a read error occurs, in which case the
error indicator for the stream (see ferror(3)) is set, and
errno is set indicate the error.
scanf returns the number of input items successfully matched and assigned. Compare its return value to the number you expect in order to detect errors.
while (scanf("%d",&val) != 1)
printf("Try again.\n");
Use
#pragma warning(disable:<warning number>)
scanf("%d",&val);
#pragma warning(default:<warning number>)
And your compiler will suppress that warning.
The best practice is to assign the return value of scanf to see if all (or how many) items were read. In this particular case, if it returns anything but 1, something went wrong (e. g. you wanted a number but the user is giving you unprintable characters) and you should handle it appropriately.
If you want your code to be robust in the presence of bad input, don't use scanf("%d", ...).
For most errors, scanf("%d", &val) will return 0 to indicate that it wasn't able to read an int value (for example, if the input is "foo" rather than "123").
But if the input is syntactically valid but out of range (for example 9999999999999999999), the behavior is undefined.
Most implementations will probably behave sanely, but I don't know how much consistency there is.
To read an int value safely, use fgets() (not gets()) followed by strtol(). (fgets() can have problems with very long input lines, but there are ways to deal with that.)