使用printf打印字符

31

这两段代码是相同的吗?

char ch = 'a';
printf("%d", ch);

它会打印出一个垃圾值吗?

我对此很困惑。

printf("%d", '\0'); 

这段代码会打印出0还是垃圾值?因为当我执行这段代码时

printf("%d", sizeof('\n')); 

它打印出4。为什么sizeof('\n')是4个字节呢?在C++中相同的东西打印1个字节。那是因为什么呢?

所以这里是主要问题

在C语言中,printf("%d", '\0')是否应该打印0?

而在C++中,printf("%d", '\0')是否应该打印垃圾值?

6个回答

54

%d打印一个整数:它将打印出您字符的ASCII表示。你需要的是%c

printf("%c", ch);

printf("%d", '\0'); 的输出结果是字符 '\0' 的 ASCII 码,即 0(通过对 0 进行转义,告诉编译器使用 ASCII 值 0)。

printf("%d", sizeof('\n')); 的输出结果是 4,因为在 C 语言中,字符字面量被视为 int 而不是 char


@nightcracker: 嗯?如果printf("%d", ch);“打印出一些垃圾值”,我猜这是因为他想要打印出A,而不是它的ASCII值... - peoro
他从未说过任何打印垃圾值的话,他只是问它是否会这样做。 - orlp
@nightcracker:嗯,有什么区别吗?我不明白你的意思。 - peoro
简单来说,你的回答并不是 OP 问题的答案。他只是对 %d 打印字符的结果感到好奇,而 %c 则完全无关。 - orlp
10
这其实正是我一直在寻找的内容(通过搜索引擎找到了这里)。即使它并没有回答原帖提出的问题,它仍然能够帮助其他人。 - bobroxsox
显示剩余3条评论

9

这应该输出字符的ASCII值,因为%d是整数的转义序列。所以在打印时,作为printf参数给定的值将被视为整数。

char ch = 'a';
printf("%d", ch);

同样适用于printf("%d", '\0');,其中空字符被解释为整数0。
最后,sizeof('\n')的结果是4,因为在C语言中,这种字符的表示法代表相应的ASCII整数。因此,'\n'作为整数与10相同。
一切都取决于您对字节的解释。

+1 所以 printf("%d", ch) 将输出 (int) 97,而 printf("%d", '\0') 将输出 (int) 0。 - BlackBear
我会这样说:“所以 '\n' 是一个 int,32 位,4 字节,sizeof() 返回 4。'\n' 的 是 10,十进制。在 ASCII 中是 NEWLINE。”原始的单句话是正确的,但可能太简洁了。 - Bill IV

7
在C语言中,char类型在表达式中会被提升为int类型。如果你深思熟虑,这基本上解释了每一个问题。
参考来源:《C程序设计语言》Brian W.Kernighan和Dennis M.Ritchie著
如果你想学习C语言,这是必读的。
此外,请参见此Stack Overflow页面,那里有比我更有经验的人可以更好地解释它。

@BlackBear:是的,因为(在大多数系统上)char是一个字节,而int是四个字节,所以这是一种提升。 - orlp
我只是引用书中的话,他们使用了“promotion”这个词。我认为这与int强制转换是相同的。 - orlp
我给你的链接点个赞。不过“促销”这个词还是有点让我困惑,但我觉得你表达得很清楚。 - user418748
术语“promotion”也在C语言标准第6.3.1.1节中使用。 - John Bode
1
晋升说明不是很精确。如果ch是char,那么sizeof(ch)为1,但sizeof('a')为4。在C中,表达式'a'与(int) 97相同。没有晋升。然而,在C ++中,该表达式的类型为char。 - scoffey

7
在C语言中,字符常量表达式例如'\n''a'的类型为int(因此sizeof '\n' == sizeof (int)),而在C ++中它们的类型为char
语句printf("%d", '\0');应该只是打印0;表达式'\0'的类型为int,其值为0。
语句printf("%d", ch);应该打印ch的整数编码(对于ASCII,'a' == 97)。

4
#include <stdio.h>
#include <stdlib.h>

int func(char a, char b, char c) /* demonstration that char on stack is promoted to int !!!
                                    note: this promotion is NOT integer promotion, but promotion during handling of the stack. don't confuse the two */
{
  const char *p = &a;
  printf("a=%d\n"
         "b=%d\n"
         "c=%d\n", *p, p[-(int)sizeof(int)], p[-(int)sizeof(int) * 2]); // don't do this. might probably work on x86 with gcc (but again: don't do this)
}


int main(void)
{
  func(1, 2, 3);

  //printf with %d treats its argument as int (argument must be int or smaller -> works because of conversion to int when on stack -- see demo above)
  printf("%d, %d, %d\n", (long long) 1, 2, 3); // don't do this! Argument must be int or smaller type (like char... which is converted to int when on the stack -- see above)



  // backslash followed by number is a oct VALUE
  printf("%d\n", '\377');             /* prints -1   -> IF char is signed char: char literal has all bits set and is thus value -1.
                                                     -> char literal is then integer promoted to int. (this promotion has nothing to do with the stack. don't confuse the two!!!) */
                                      /* prints 255  -> IF char is unsigned char: char literal has all bits set and is thus value 255.
                                                     -> char literal is then integer promoted to int */


  // backslash followed by x is a hex VALUE
  printf("%d\n", '\xff');             /* prints -1   -> IF char is signed char: char literal has all bits set and is thus value -1.
                                                     -> char literal is then integer promoted to int */
                                      /* prints 255  -> IF char is unsigned char: char literal has all bits set and is thus value 255.
                                                     -> char literal is then integer promoted to int */


  printf("%d\n", 255);                // prints 255


  printf("%d\n", (char)255);          // prints -1   -> 255 is cast to char where it is -1
  printf("%d\n", '\n');               // prints 10   -> Ascii newline has VALUE 10. The char 10 is integer promoted to int 10
  printf("%d\n", sizeof('\n'));       // prints 4    -> Ascii newline is char, but integer promoted to int. And sizeof(int) is 4 (on many architectures)
  printf("%d\n", sizeof((char)'\n')); // prints 1    -> Switch off integer promotion via cast!

  return 0;
}

2
请将每行限制在90个字符以内。您的一半文本已被隐藏。 - A.L
责怪那些疯狂的16:9高分辨率显示器!有了程序员友好的4:3宽高比,就不会有人写出如此疯狂的长行代码了 ;) - BitTickler

-2

是的,除非你很幸运,否则它会打印垃圾。

非常重要。

printf/sprintf/fprintf参数的类型必须与相关格式类型字符匹配。

如果类型不匹配并且编译通过,则结果非常未定义。

许多较新的编译器知道printf并发出警告,如果类型不匹配。如果您收到这些警告,请修复它们。

如果您想将变量函数的参数类型转换,必须提供强制转换(即显式转换),因为编译器无法确定需要执行转换(就像具有类型化参数的函数原型一样)。

printf("%d\n", (int) ch)

在这个例子中,printf 被告知栈上有一个 "int"。强制转换确保无论 sizeof 返回什么(通常是某种长整型),printf 都会得到一个 int。
printf("%d", (int) sizeof('\n'))

1
几乎所有的东西都是错误的。假设printf的原型可见,由于变参函数中发生了整数提升,将char或short传递给%d是完全可以的。最好情况下,强制转换是愚蠢的。 - Jens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接