【问题标题】:printf value in union depending on format联合中的 printf 值取决于格式
【发布时间】:2014-05-30 23:53:17
【问题描述】:

根据格式说明符,可以将scanf 值合并到一个联合中。

union {
    int i;
    double f;
} u;

scanf("%lf", &u.i); // implicitly scan the double

printf("%lf", u.f); // explicitly print the double

这是可行的,因为scanf 将指针作为参数,并且联合中的所有元素都是对齐的,(void*)&u.i == (void*)&u.f

是否可以更改printf 行以执行相同的操作,根据格式从联合中选择要打印的正确值,而不会意外切割一些可能的值?

printf("%lf", ???); // implicitly print the double

【问题讨论】:

  • 与您的问题无关,但请记住 sizeof(int) 可能与 sizeof(double) 不同(很可能不是)。

标签: c printf scanf unions


【解决方案1】:

printf 无法推断传递给它的参数的类型。该参数将根据格式字符串中的相应转换说明符进行解释。因此,参数必须正确对应于它们各自的转换说明符。引用 C11 标准 § 7.21.6.1 ¶9 关于 fprintf

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

再次引用 C11 标准 § 7.21.6.2 ¶13 关于fscanf

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

因此,对scanf 的以下调用会调用未定义的行为,因为u.i 的类型是int,但%lf 转换说明符意味着您正在阅读double

scanf("%lf", &u.i);

请阅读这些 -

  1. What happens when I use the wrong format specifier?
  2. Wrong format specifiers in scanf or printf

此外,访问最近未编写的联合字段是未定义的行为。

union {
    int i;
    double f;
} u;

// undefined behaviour. u.i is of type int but %lf
// means scanf will read a double
scanf("%lf", &u.i);

// undefined behaviour because reading the field u.f
// but the last written field is u.i
printf("%lf", u.f);

【讨论】:

  • scanf("%lf", &u.i); 中也有 UB 函数需要 double* 但给出的是 int*
【解决方案2】:

不,你不能那样做。

没有间接的printf() 格式说明符,联合的不同成员可以有不同的大小,因此作为可变参数进行不同的处理。

即使有办法说“指向整数的指针”而不仅仅是“整数”,当然仍然没有办法让printf() 在“指向整数的指针”和“指向双精度的指针”之间做出决定只在那个指针值上。

如果我理解正确,你会喜欢这样的:

printf("%>g\n", &u);  /* prints the double */
printf("%>d\n", &u);  /* prints the int */

我发明了(!)> 格式修饰符来表示“参数是指向相应数据类型的指针,即>g is "pointer todouble`”。遗憾的是,这不是标准的。你当然可以自己实现。

【讨论】:

  • 不仅在指针的值上,而且在格式字符串中,我告诉printf要查找什么。就像scanf 的情况一样。
猜你喜欢
  • 2020-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多