布尔类型的值在C中更改

Nat*_*ent 7 c boolean scanf

我注意到在C中,我的布尔变量以某种我不理解的方式被改变了.

#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;
}
Run Code Online (Sandbox Code Playgroud)

如果我输入1for的x值和y(1在此示例中)的任何值:

x: 1
x is 1
y: 1
x is 0
y is 1
Run Code Online (Sandbox Code Playgroud)

最后,y输出正确的原始值,但x神奇地改变0之间!

这不是一个问题,当用于输入x0因为对于两个输出xy如预期的是其各自的原始值.

请解释发生了什么!

koc*_*ica 8

您正在将boolean变量的地址传递给scanf()期望变量类型int*.这将调用未定义的行为,您可能会得到错误的结果甚至崩溃.

要解决此问题,请使用临时int存储扫描布尔值(作为int),然后将其存储为布尔变量.

演示

bool x, y;
int tmp;

printf("x: ");
scanf("%d", &tmp);
x = tmp;
Run Code Online (Sandbox Code Playgroud)

另一方面,打印boolan变量是不同的故事,其中布尔值被赋予int而没有任何问题并且正确打印.


Sou*_*osh 7

好的,这里有两点.

  1. 大小bool是实现定义的.
  2. bool标准中没有为类型定义格式说明符.

因此,尽管扫描值,传递的地址bool作为参数%d不好见注为所提供的类型是不一样的预期类型.

您可以使用中间整数,将值扫描到该值,并且(在验证或转换为truefalseMACRO之后)将结果分配回bool类型变量.

但是,对于打印,由于默认参数提升,a bool可以成为参数的候选者%d而没有问题.


注意:

%d*scanf()预计的说法是一个int *,而不是提供一个bool*会导致 不确定的行为.

相关的,引用章节第7.21.6.2节第10段

[....]除非由a指示赋值抑制,否则*转换的结果将放置在format尚未收到转换结果的参数后面的第一个参数所指向的对象中.如果此对象没有适当的类型,或者无法在对象中表示转换结果,则行为未定义.

  • @AndreKampling没有太大的相关性,因为即使对于具有相同大小的两种类型,使用不匹配的格式说明符仍然是未定义的行为 (3认同)

And*_*nle 7

A bool不是int.使用%d格式说明符读取它int是未定义的行为.

根据7.21.6.2 fscanfC标准第13段功能:

如果转换规范无效,则行为未定义.

注意7.21.6.1fprintf第9段功能说明:

如果转换规范无效,则行为未定义.如果任何参数不是相应转换规范的正确类型,则行为未定义.

但这是为了fprintf(),而不是fscanf().格式说明符对于scanf()函数来说要严格得多,因为没有参数提升允许一种格式,例如%d"为"工作"工作",char或者bool被提升为int一个printf()调用.该scanf()函数传递的地址参数的,如果有什么地址指的是从什么是每个格式说明符预期错误的大小,不确定的行为会导致-如不明原因更改另一个变量.

  • 这是错误的。此处的转换规范不是无效的__。见[this](/sf/ask/3191188381/) (2认同)

msc*_*msc 5

bool然后是一种不同的数据类型int,它可能是一个单字节.

scanf不是类型安全的函数,你用%d转换说明符告诉它需要指向int的指针,并且scanf无法知道你已经传递pointer to bool而不是指向int指针.然后,您将获得未定义的行为.

clang编译生成警告:

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);
          ~~   ^~
Run Code Online (Sandbox Code Playgroud)