【问题标题】:Is printf's conversion specifier equivalent to function declaration?printf 的转换说明符是否等同于函数声明?
【发布时间】:2013-07-22 01:24:46
【问题描述】:

就编译器类型检查和自动转换而言,printf 的转换说明符是否等同于函数声明?

我正在尝试了解 C 基本数据类型的自动类型转换、促销等,我想知道是否可以使用 printf 而不是虚拟函数来检查发生了什么。

举个例子让我的问题更清楚,

void f1 (int a){}

int main() { f1('c'); return 0; }

帮助我理解如果我声明一个带有 int 参数的函数但在调用中传递 char 类型会发生什么。

我想知道我是否可以打电话

printf("%i", 'c');

出于上述目的。

另外,如果有人能指出一些关于 C 中类型表示/转换/推广的权威资源(在网络或书籍上),我将不胜感激。

【问题讨论】:

  • 您的示例没有多大帮助,因为在 C 中所谓的“整数字符常量”,例如 'c' 已经属于 int 类型。所以我们将这样一个常量传递给一个需要 int 的函数,你永远不会看到警告,因为一切都很好。
  • @JensGustedt 这就是我实验的首要目的——理解你提到的那些点。当需要一种类型而传递另一种类型时,它是如何工作的——char、int、long。浮点数、字符串、指针等。这里给出的是最基本的。

标签: c function printf type-conversion


【解决方案1】:

没有。

许多编译器不对格式字符串进行任何类型检查。当使用-Wformat 时,gcc 会这样做,但这些检查与分配时进行的检查是分开的。

printf 的参数按原样传递。唯一的转换可能是将其增加到处理器字大小(这就是char 变为int 的方式)并且它不以任何方式依赖于格式字符串。请参阅 Jonathan Leflfer 的评论,该评论更准确地解释了这一点。

【讨论】:

  • 实际上,charunsigned charsigned charshortunsigned short 类型都被提升为 int(或 unsigned int 偶尔——尽管这些天很少见),并且float 被提升为double。一旦您到达参数列表的可变部分(... 省略号),所有具有可变参数列表的函数都会发生这种情况;当您调用范围内没有原型的函数时也会发生这种情况(您不应该这样做,但确实会发生)。
  • @undefinedbehaviour,我将c称为char,但实际上我认为它是int
  • 是的。像 'c' 这样的字符文字实际上是 C 中的 int 值。
【解决方案2】:

printf 的转换说明符是否等同于函数声明为 至于编译器类型检查和自动转换?

没有。当您将char 传递给可变参数函数时,您传递的值将被提升为int。这与您使用的转换说明符无关。 C11 standard 在 §6.5.2.2p7 中对此进行了描述:

函数原型声明器中的省略号表示 参数类型转换在最后一个声明的参数之后停止。 默认参数提升是在尾随参数上执行的。

默认参数提升在 §6.5.2.2p6 中定义为整数提升的超集:

...对每个参数执行整数提升,并且 类型为 float 的参数被提升为 double。这些是 称为默认参数promotions

... 和整数提升在 §6.3.1.1p2 中定义:

如果int 可以表示原始类型的所有值(受限制 通过宽度,对于位域),值被转换为int; 否则,它将转换为unsigned int。这些被称为 整数促销


举个例子让我的问题更清楚,

void f1 (int a){}

int main() { f1('c');返回0; }

帮助我理解如果我声明一个函数会发生什么 int 参数,但在调用中传递 char 类型。

不,它没有。 'c' 实际上是一个int。如果你不相信我,你自己看看:

#include <stdio.h>

#ifdef __cplusplus
#error "Don't compile C code with a C++ compiler."
#endif

int main(void) {
    printf("sizeof 'c': %zu\n", sizeof 'c');
}

【讨论】:

  • 感谢您的详细回答和关于“c”的观点。当我有足够的积分时,我会记得投票。感谢您也链接标准 - 完成这可能是我现在需要的。
  • @Lavya 如果您还没有,我建议您阅读并在 K&R(Kernighan 和 Ritchie)中进行练习。一旦你这样做了,H&S (Harbison & Steele) 就会有一本可能很有趣的参考书。
  • 是的,现在通过 Ritchie。我也会尝试接触 H&S。谢谢!
【解决方案3】:

printf("%i", 'c');你会得到字符'c'的ASCII值,即99。char到int有两种方法。

如果您只想要 char 的 ASCII 值,只需使用整数说明符打印 char

如果您想将char 转换为整数(如 '0' 为 0 或 '1' 为 1),则需要执行以下操作

char a = '4';
int ia = a - '0';  //subtraction of '0'

只是为了更清楚起见,printf 中的说明符表示要从堆栈中弹出多少。如果是%d,则弹出4 bytes(假设为4字节的int)如果是%c,则弹出1 byte

【讨论】:

  • 谢谢 - 你的最后一行让我思考。
  • ASCII?为什么'c'一定要对应99?如果使用 EBCDIC 会怎样?您是否知道 %c 指令对应于 int 参数?
  • @undefinedbehaviour 是的,我知道 C 总是将类型提升到至少 int。这里我说的是 printf 输出,它将是 99,这是 char 'c' 的 ASCII 值
  • 那我建议把最后一句改成%d%c对应的类型相同。为了准确起见,在第一句话中不使用“ASCII”可能是个好主意:printf("%d", 'c'); 将打印与字符文字 'c' 对应的整数值。
【解决方案4】:

当您将 'c' 作为参数传递给函数 f1 时,字母 c (99) 会存储到 a 中。所以如果你修改下面的 f1 函数

void f1 (int a){
 printf("\n %d",a); // prints the ascii value of charecter c
 printf("\n %c",a); //prints the o/p as c
 printf("\n %i",a); //prints the ascii value of charecter c again 
}

O/p for the program

99
c
99

你问了

I want to know if I can just call printf("%i", 'c');

可以,那么就不需要实现f1函数了。

【讨论】:

  • ASCII?为什么'c'一定要对应99?如果改为使用 EBCDIC 会怎样?
猜你喜欢
  • 2012-06-30
  • 2012-03-14
  • 2018-03-30
  • 2017-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-08
相关资源
最近更新 更多