在 3 个相同的 sscanf 调用中,中间的一个不起作用

问题描述 投票:0回答:2

我不知道发生了什么

在我的 C++ 程序中,我想简单地从命令行读取一些参数。

  1. 变量在 main() 的开头定义:
    uint32_t sampling_frequency;
    uint32_t samples_per_pixel;
    uint32_t total_samples;
    uint16_t amplification;
  1. 对 argc 进行一些验证后,我正在阅读它们:
    sscanf(argv[3], "%" PRIu32, &sampling_frequency); 
    sscanf(argv[4], "%" PRIu32, &samples_per_pixel);
    sscanf(argv[5], "%" PRIu16, &amplification);
  1. 之后立即打印获取的值以进行调试:
    printf("%s: %" PRIu32 "\n", argv[3], sampling_frequency);
    printf("%s: %" PRIu32 "\n", argv[4], samples_per_pixel);
    printf("%s: %" PRIu16 "\n", argv[5], amplification);
  1. 当我运行程序时,最大的惊喜来了:
4.b:~/pro/spectr> ./spectr spectr_02.png out.wav 44100 10 2 -9 -8 -5 -4 -2 0 2 3 5
44100: 44100
10: 0
2: 2

如您所见,3 个 sscanf() 是相同的,但由于某些无法解释的原因,它仅对 argv[4] 无法正常工作。 问题出在 sscanf() 而不是 printf(),因为代码稍后检查数值并且它的行为确实就像是 0。 我不知道为什么它会这样。

我在 Debian10 amd64 上使用 g++ 进行编译。

c++ scanf
2个回答
4
投票

PRI*
宏仅适用于打印,不适用于扫描。

如果您想将这些宏与

sscanf()
一起使用,则需要使用
SCN*
版本。

像这样:

sscanf(argv[3], "%" SCNu32, &sampling_frequency); 
sscanf(argv[4], "%" SCNu32, &samples_per_pixel);
sscanf(argv[5], "%" SCNu16, &amplification);

0
投票

您对 scanf 使用了错误的格式说明符宏。 “PRI”宏适用于 printf 系列。 “SCN”宏适用于 scanf 系列。

由于整数提升适用于可变参数,因此 printf 仅需要大于 int 的类型的大小说明符。对于小于 int 的类型和大于 int 的类型,scanf 都需要它们。

您的平台有一个 32 位 int 和一个 16 位 Short。所以宏可能类似于 .

#define PRIu16 "u"
#define PRIu32 "u"
#define SCNu16 "hu"
#define SCNu32 "u"

因此,您对 scanf 的 PRIu16 宏的错误使用会导致您将 4 个字节读取到 2 个字节的变量中。由于您的系统是小端字节序并且可以接受未对齐的访问,因此可以将值正确读取到 uint16_t 中,但也会覆盖内存的接下来两个字节。该内存中到底有什么取决于编译器如何在堆栈上分配变量,

在您的情况下,似乎

amplification
直接分配在
samples_per_pixel
下面。因此,将四字节值读入
amplification
会覆盖
samples_per_pixel
的前两个字节。

© www.soinside.com 2019 - 2024. All rights reserved.