C sscanf(“%hhx”)读取无符号整数而不是无符号字符

C sscanf(“%hhx”)读取无符号整数而不是无符号字符,c,scanf,C,Scanf,我们使用sscanf将十六进制值转换为字符串,如下所示: 包括 包括 int main{ 字符数据[]=41424344; 无符号整数结果=0; sscanfdata,%hhx,&结果; printf%x\n,结果; 结果=0; SSCANF数据,%2x,&结果; printf%x\n,结果; 结果=0; sscanfdata,%2hhx,&结果; printf%x\n,结果; 返回0; } 输出: 41424344 41 41 从第一个输出中,我们可以看到sscanf%hhx读取了整个4个字

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

包括 包括 int main{ 字符数据[]=41424344; 无符号整数结果=0; sscanfdata,%hhx,&结果; printf%x\n,结果; 结果=0; SSCANF数据,%2x,&结果; printf%x\n,结果; 结果=0; sscanfdata,%2hhx,&结果; printf%x\n,结果; 返回0; } 输出:

41424344
41
41
从第一个输出中,我们可以看到sscanf%hhx读取了整个4个字节,而不是1个字节的无符号字符。为什么?

由于格式说明符和参数类型不匹配,导致行为未定义

例如,hh前缀意味着参数必须是无符号字符*,这与传递的无符号int*完全不同

实际上,%2hhx格式也存在此问题。

由于格式说明符和参数类型不匹配,行为未定义

例如,hh前缀意味着参数必须是无符号字符*,这与传递的无符号int*完全不同

实际上,%2hhx格式也存在此问题

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

好吧,你的代码除了十六进制到字符串之间的转换器外什么都是。您的代码只接受一个字符串,并尝试根据解释的字符转换为十六进制数进行输出。因此,如果我将自己与上述第一段联系起来,一个简单的解决办法是:

#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));
}
如果我使用-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。你可能是用C++编译器编译这个代码吗? 出于这一点和其他原因,我建议你阅读,一旦你阅读了,就用一段代码发布你的问题,这段代码实际上显示了你所说的。如果你认为我们有一些魔术来猜测你的意图,你尝试了什么,我们还必须纠正你在帖子上的打字错误,我们在你的问题上浪费了很多时间,这可能对你有好处,因为你学到了很多。。。但这对其他需要帮助的人来说是可怕的。规范和文件仅供阅读。。。不是为了让别人帮你读

下次你发帖的时候。请测试您将要发送的示例代码,只是为了检查它不会给出测试用例中没有的新错误和警告。一旦你测试了代码,复制并粘贴它,所有的包含文件和我们编译和测试所需的一切如果我们需要提供你不需要的一切,你可以在未发布的代码中隐藏错误,我们不会看到任何奇怪的东西,只会看到很多打字错误

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

好吧,你的代码除了十六进制到字符串之间的转换器外什么都是。您的代码只接受一个字符串,并尝试根据解释的字符转换为十六进制数进行输出。因此,如果我将自己与上述第一段联系起来,一个简单的解决办法是:

#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));
}
如果我使用-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。你可能是用C++编译器编译这个代码吗? 出于这一点和其他原因,我建议你阅读,一旦你阅读了,就用一段代码发布你的问题,这段代码实际上显示了你所说的。如果你认为我们有一些魔术来猜测你的意图,你尝试了什么,我们还必须纠正你在帖子上的打字错误,我们在你的问题上浪费了很多时间,这可能对你有好处,因为你学到了很多。。。但这对其他需要帮助的人来说是可怕的。规范和文件仅供阅读。。。不是为了让别人帮你读


下次你发帖的时候。请测试您将要发送的示例代码,只是为了检查它不会给出测试用例中没有的新错误和警告。一旦您测试了代码,复制并粘贴它,包括所有包含文件以及我们编译和测试所需的一切如果我们需要提供您不需要的一切,您可以将错误隐藏在未发布的代码中,我们不会看到任何奇怪的情况,但会看到很多键入错误。

您是在诊断打开的情况下编译的吗?使用gcc-Wformat可以得到:警告:format指定类型为“unsigned char*”,但参数的类型为“unsigned int*”,可能该消息应该用它来增强,这将导致未定义
您的代码看起来更像是一个测试,让我们猜测应该得到什么样的输出,而不是您遇到的问题。。。。你能把你期望的代码输出吗?您使用无符号字符格式说明符调用scanf,但不是传递指向无符号字符的指针,而是传递指向无符号整数的指针,这是未定义的行为。顺便说一下,您的代码无法将十六进制数据转换为字符串,因为它正在扫描字符串中的数字数据,所以它是否与您所说的正好相反?您是否在诊断打开的情况下编译?使用gcc-Wformat,您会得到:警告:format指定类型为“unsigned char*”,但参数的类型为“unsigned int*”,可能该消息应该用它进行增强,这将导致未定义的行为。您的代码看起来更像是一个测试,让我们猜测应该输出什么,而不是您遇到的问题。。。。你能把你期望的代码输出吗?您使用无符号字符格式说明符调用scanf,但不是传递指向无符号字符的指针,而是传递指向无符号整数的指针,这是未定义的行为。顺便说一下,您的代码无法将十六进制数据转换为字符串,因为它正在扫描字符串以查找数字数据,所以您说的是相反的吗?