为什么在scanf中需要使用%hd?

7
我创建了一个非常简单的带有菜单的程序,它接受一个值,然后将其存储到本地变量值中,并最终通过第二个选项打印该值。
我的问题是: 为什么只有在scanf参数中添加"h"时程序才能工作? 换句话说:scanf()和我的本地int值变量之间有什么关系?
谢谢!
附注:(我使用Dev-C++(GCC)进行编译。在Visual Studio中它可以工作)
#include <stdio.h>

main () {

    int value = 0;
    short choice = 0;

    do {
       printf("\nYour Choice ---> ");
       scanf("%d", &choice);  /* replace with "%hd" and it works */

       switch (choice) {
          case 1:
               printf("\nEnter a volue to store ");
               scanf("%d", &value);
               getchar();              
               printf("\nValue: %d", value);
               break;
          case 2:
               printf("\nValue: %d", value);            
               break;  
       }

    } while (choice < 3);

    getchar();
}

抱歉文本格式不佳。 - Mario
9个回答

14
使用 scanf 函数,"h" 修饰符表示读取一个 short 类型的整数,而你的变量 choice 恰好就是 short 类型的。因此 "%hd" 是必需的,它可以只写入两个字节(大多数机器上),而不是 "%d" 写入的 4 个字节。
了解更多信息,请查看此 scanf 参考页面

1
你好,%hd 确实可行,但是为什么这些 维基百科条目cplusplus 条目 没有提到它呢?事实上,它们都声明应该使用 %h - Scaramouche

2
变量choice的类型是short,因此在scanf中需要使用%h来读取它(实际上这里不需要d)。而int类型只需要%d。有关转换的说明,请参见此处

是的,我知道,但问题是为什么由于缺少这个“h”,我的程序无法将值存储到int value变量中? - Mario
@Mario:因为scanf将"%hd"定义为“读取两个字节(在32位平台上)并将其放入short int数据类型中”。 - Randolpho

1
您正在读取一个短整型。h 是必需的,因为%d默认情况下是int的大小。请参阅 scanf 参考页面

1

看起来你的问题在于choice是一个short,它(通常)是2个字节长,而%d期望一个整数,它(通常)是4个字节长…因此scanf会覆盖栈上choice之后的任何内容。


1

choice 是一个 short,而 %d 指定了一个 int

当你指定 %d 时,scanf 必须假设相关的参数是一个指向大小为 int 的内存块的指针,并将一个 int 写入其中。当这种情况发生时,它可能会写入与但不属于 choice 的数据,结果是未定义的,可能不好!如果它在一个编译器中工作而在另一个编译器中不工作,那只是未定义行为的本质!

在 GCC 中,-Wformat 应该在出现此错误时给出警告。



0

%d 用于读取 int,而不是 short。你的代码从来没有真正“工作”过——在这种情况下,你似乎没有注意到你想要的和你得到的未定义行为之间的区别。


0
scanf输入short类型变量的修饰符是%hd。因此,您需要指定正确的修饰符。
scanf("%d",&integer);  // For integer type
scanf("%hd",&short_int); // For short type

因此它不起作用。

0

根据数字填充、字节序等问题,您可能会将输入值的上半部分或下半部分存储到choice中;您将输入值的其余部分存储到内存中,该内存可能正在用于其他用途。


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