Boolean type value changed to C

I noticed that in C my boolean variable is somehow changing, so I don't understand.

#include <stdio.h> #include <stdbool.h> int main(void) { bool x, y; printf("x: "); scanf("%d", &x); printf("x is %d\n", x); printf("y: "); scanf("%d", &y); printf("x is %d\n", x); printf("y is %d\n", y); return 0; } 

If I enter a value of 1 for x and any value for y ( 1 in this example):

 x: 1 x is 1 y: 1 x is 0 y is 1 

in the end, y prints the correct initial value, but x magically changes to 0 between them!

This is not a problem when the input for x is 0 , since the outputs for x and y are their respective initial values, as expected.

Please explain what is happening!

+7
c boolean scanf
source share
7 answers

You pass the address of a boolean variable to scanf() , which expects a variable of type int* . This will cause undefined behavior, and you may get incorrect results or even crash.

To solve this problem, use a temporary int to store a scan of a boolean value (like an int) and after that save it in a variable of type boolean.

Demo

 bool x, y; int tmp; printf("x: "); scanf("%d", &tmp); x = tmp; 

On the other hand, another story is used to print the boolan variable, where the boolean value is stamped to int without any problems and printed correctly.

+8
source share

OK, two points here.

  • The size of the bool is determined by the implementation.
  • There is no format specifier for the bool type in the standard.

So, while scanning the value by passing the bool address as an argument to %d is bad, see note because the supplied type is not the same as the expected type.

You can use an intermediate integer, scan the value into it and (after checking or converting to true and false MACRO) assign the result back to the bool variable.

However, for printing, because of raising the default argument, bool can be a candidate for the %d argument without any problems.


Note:

%d with *scanf() expects the argument to be int * , instead supplying bool* will cause undefined behavior .

Related, citing from chapter Β§7.21.6.2, paragraph 10

[....] If assignment suppression was not specified a * , the conversion result is placed in the object pointed to by the first argument, the next argument format , which has not yet received the conversion result. If this object does not have the appropriate type or if the result of the conversion cannot be represented in the object, undefined behavior.

+7
source share

A bool not an int . Reading it using the %d format specifier for int is undefined behavior.

Per 7.21.6.2 fscanf Function , paragraph 13 of the C standard :

If the conversion specification is not valid, the behavior is undefined.

Please note that clause 9 7.21.6.1 The fprintf function states:

If the conversion specification is not valid, the behavior is undefined. If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

But this is for fprintf() , not fscanf() . Formatting specifiers are much stricter for scanf() functions, since argument advancement will not allow the %d format to β€œwork” for char or bool , which gets an int to call printf() . The scanf() functions are passed to the address of the argument, and if what the address indicates is the wrong size from the format expected for the specifier, it will lead to undefined behavior - for example, unexplained changes to another variable.

+7
source share

bool is a different data type and then int , and it will probably be a single byte.

scanf not type safe, you tell it using the conversion specifier %d , which expects a pointer to int , and scanf does not know that you have passed pointer to bool instead of a pointer to int . Then you will get undefined behavior .

clang compiler generated warning:

 source_file.c:8:16: warning: format specifies type 'int *' but the argument has type 'bool *' [-Wformat] scanf("%d", &x); ~~ ^~ source_file.c:13:16: warning: format specifies type 'int *' but the argument has type 'bool *' [-Wformat] scanf("%d", &y); ~~ ^~ 
+5
source share

All other answers are technically correct, but they really don’t help you.

The main problem is not x and y, but that you cannot independently debug the most trivial programming problems yourself. This is easy to fix - turn on compiler warnings (when using the gcc option, add -Wall ). The compiler will inform you of such an error, and many, many others. No need to switch to stackoverflow every time :)

+3
source share

Consider the following program

 #include <stdio.h> #include <stdbool.h> int main(void) { int z, s; printf("int z: %p\nint s: %p\n", &z, &s); bool x, y; printf("bool x: %p\nbool y: %p\n", &x, &y); return 0; } 

Exit:

 int z: 0028FF3C int s: 0028FF38 bool x: 0028FF37 bool y: 0028FF36 

Now there is a 4 byte difference between z and s , which is the size of int in my case.

There is a difference of 1 byte between x and y .

Now with this line:

 scanf("%d", &y); 

From %d to scanf you indicate that you need a 4-byte long input, int .

This int will be stored in case y at address 0028FF36 and with input 0x0001 second byte, which is 0 , will be stored in 0028FF37 . And this is the address x .

You can check this with a different input value. For example, if you give 65535 in y , which is 0xFFFF , then x will be 0xF , which is 255 decimal.

0
source share

or maybe (if the input line contains true or 1 will be returned - otherwise 0 )

 int getBool(char *message) { char input[20]; printf("%s", message); fgets(input, 20, stdin); return !!strstr(strlwr(input), "true") || strtol(input, NULL, 10); } 
0
source share

All Articles