【问题标题】:C sscanf("%hhx") read an unsigned int instead of unsigned charC sscanf("%hhx") 读取一个 unsigned int 而不是 unsigned char
【发布时间】:2020-12-29 04:43:04
【问题描述】:

我们使用 sscanf() 将十六进制值转换为字符串如下:

#include <stdio.h>
#include <string>
int main() {
    char data[] = "41424344";
    unsigned int result = 0;
    sscanf(data, "%hhx", &result);
    printf("%x\n", result);
    result = 0;
    sscanf(data, "%2x", &result);
    printf("%x\n", result);
    result = 0;
    sscanf(data, "%2hhx", &result);
    printf("%x\n", result);
    return 0;
}

输出:

41424344
41
41

从第一个输出中,我们可以看到sscanf("%hhx") 读取了整个 4 个字节而不是 1 个字节(“unsigned char”)。为什么?

【问题讨论】:

  • 您编译时是否启用了诊断?使用gcc -Wformat 你会得到:warning: format specifies type 'unsigned char *' but the argument has type 'unsigned int *' 也许应该用“这将导致未定义的行为”来增强该消息。
  • 您的代码看起来更像是一个测试,让我们猜测应该预期什么输出,而不是您遇到的问题....请您输入您期望该代码输出的内容吗?您使用unsigned char 格式说明符调用scanf,但不是将指针传递给unsigned char,而是将指针传递给unsigned int,这是未定义的行为
  • 顺便说一句,您的代码无法将十六进制数据转换为字符串,因为它正在扫描字符串以查找数字数据(所以您说的正好相反?)

标签: c scanf


【解决方案1】:

未定义的行为,因为格式说明符和参数类型不匹配。

根据例如this scanf referencehh前缀表示参数必须是unsigned char *,和你传的unsigned int *完全不同。

%2hhx 格式实际上也存在这个问题。

【讨论】:

    【解决方案2】:

    我们使用 sscanf() 将十六进制值转换为字符串如下:

    好吧,您的代码只是十六进制到字符串之间的转换器。您的代码只接受一个字符串,并尝试根据将 interpreted 字符转换为十六进制数字进行输出。所以,如果我将自己与上面的第一段联系起来,一个简单的解决方案是:

    #include <stdio.h>
    
    char *toHexString(
            unsigned value, /* the value to be converted */
            char *buffer,   /* the char buffer to hold the converted data. */
            size_t buf_size)/* the size of the previous buffer */
    {
        if (!buf_size) return NULL; /* error, no space in buffer */
        char *p = buffer + buf_size; /* start at the end of buffer */
        *--p = '\0'; /* the string terminator, we go backwards */
        while (value && p > buffer) {
            *--p = "0123456789abcdef"[value & 0xf];
            value >>= 4;
        }
        if (value && p == buffer) { /* overflow */
            return NULL;
        }
        return p;
    }
    
    int main()
    {
        char buffer[20];
    
        /* we should call first the function, to check for NULL
         * return value, but we know a priori that an unsigned
         * int will be less than 20 digits (including the final
         * null char), so we don't need to check for NULL
         * return.
         */
        puts(toHexString(0x12389abcU, buffer, sizeof buffer));
    }
    

    很抱歉完全忽略了您的代码,但正如所写,它什么也不做,甚至近似于您假装的内容,转换十六进制数(我使用十六进制 unsigned int 文字 0x12389abcU)并打印字符串(在toHexString()返回的指针)。


    注意

    • 您的代码未使用默认编译器参数进行编译。它给出了以下两个错误:
    pru2.c: In function ‘main’:
    pru2.c:7:22: error: format ‘%hhx’ expects argument of type ‘unsigned char *’, but argument 3 has type ‘unsigned int *’ [-Werror=format=]
        7 |     sscanf(data, "%hhx", &result);
          |                   ~~~^   ~~~~~~~
          |                      |   |
          |                      |   unsigned int *
          |                      unsigned char *
          |                   %x
    pru2.c:13:23: error: format ‘%hhx’ expects argument of type ‘unsigned char *’, but argument 3 has type ‘unsigned int *’ [-Werror=format=]
       13 |     sscanf(data, "%2hhx", &result);
          |                   ~~~~^   ~~~~~~~
          |                       |   |
          |                       |   unsigned int *
          |                       unsigned char *
          |                   %2x
    cc1: all warnings being treated as errors
    *** Error code 1
    

    如果我使用--std=c89 编译它,这些错误就会变成警告并允许获取可执行文件:

    lcu@titan:~/git/cornucopia$ make CFLAGS='--std=c89' pru2
    cc --std=c89   -o pru2 pru2.c 
    pru2.c: In function ‘main’:
    pru2.c:7:22: warning: format ‘%hhx’ expects argument of type ‘unsigned char *’, but argument 3 has type ‘unsigned int *’ [-Wformat=]
        7 |     sscanf(data, "%hhx", &result);
          |                   ~~~^   ~~~~~~~
          |                      |   |
          |                      |   unsigned int *
          |                      unsigned char *
          |                   %x
    pru2.c:13:23: warning: format ‘%hhx’ expects argument of type ‘unsigned char *’, but argument 3 has type ‘unsigned int *’ [-Wformat=]
       13 |     sscanf(data, "%2hhx", &result);
          |                   ~~~~^   ~~~~~~~
          |                       |   |
          |                       |   unsigned int *
          |                       unsigned char *
          |                   %2x
    

    但编译后,我得到了完全不同的输出:

    lcu@titan:~/git/cornucopia$ pru2
    44
    41
    41
    

    这不是您在问题中所说的。顺便说一句,我不得不将#include &lt;string&gt; 修复为#include &lt;string.h&gt; 以前的错误。 (你可能是用 c++ 编译器编译这段代码吗?)

    出于这个原因和其他原因,我建议您阅读How to create a Minimal, Reproducible Example,一旦您阅读了它,使用实际显示您所说内容的代码发布您的问题。如果您认为我们有一些神奇地猜测你的意图,你尝试了什么,我们还必须纠正你在帖子上的打字错误,我们在你的问题上浪费了很多时间,这可能对你有好处,因为你学到了很多......但对于其他需要帮助的人来说,这很可怕。规范和文档是用来阅读的......不是为了让别人为你阅读它们。

    下次您发布问题时。请测试您要发送的示例代码,以检查它是否不会给出您的测试用例中没有的新错误和警告。 一旦您测试了代码,请按原样复制并粘贴所有包含的文件以及我们编译和测试所需的一切如果我们需要提供您不需要的所有内容,您可以隐藏未发布代码中的错误,我们不会看到什么奇怪的东西,但是会出现很多打字错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-06
      • 1970-01-01
      • 2012-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-04
      • 1970-01-01
      相关资源
      最近更新 更多