【问题标题】:Hexadecimal representation of generic data type value in C [duplicate]C中通用数据类型值的十六进制表示
【发布时间】:2017-08-31 22:58:23
【问题描述】:

我试图用 C 语言编写一个函数来打印出通用数据类型值的十六进制表示。我第一次尝试失败,第二次成功,为什么?

  1. 第一次尝试

    #include <stdio.h>
    
    /* prints out the hexadecimal representation of a generic value */
    void show_hex(void*,size_t);
    
    int main() {
        int i = 12345;
        short s = 32767; /* 2^15 - 1 */
        show_hex(&i, sizeof(int));
        show_hex(&s, sizeof(short));
        return 0;
    }
    
    void show_hex(void *x, size_t sz){
         char *cx = x;
         int i;
         printf("0x");
         for (i = 0; i < sz; ++i)
             printf("%.2x", cx[i]);
         printf("\n");
    }
    

    输出:0x39300000 用于 int 情况,正如在 little endian 机器 (Mac OSX) 上所预期的那样。对于short 的情况,它输出0xffffffff7f 而不是0xff7f

  2. 第二次尝试:

    typedef unsigned char *byte_pointer;
    
    int main() {
        int i = 12345;
        short s = 32767; /* 2^15 - 1 */
        show_hex((byte_pointer)&i, sizeof(int));
        show_hex((byte_pointer)&s, sizeof(short));
        return 0;
    }
    
    void show_hex(byte_pointer x, size_t sz){
        int i;
        printf("0x");
        for (i = 0; i < sz; ++i)
            printf("%.2x", x[i]);
        printf("\n");
    }
    

    此程序在两种情况下都按预期输出 int: 0x39300000short: 0xff7f

【问题讨论】:

  • 对于第一种情况,将printf("%.2x", cx[i]);更改为printf("%.2x", cx[i] &amp; 0xFF);。普通的char 类型是有符号的,因此 0xFF 被符号扩展为一个全为 F 的 8 字节值,如打印输出所示。使用printf() 和其他可变参数函数,参数列表的... 部分中的参数默认提升,因此char 提升为int(与short 一样),float 提升为@987654339 @.
  • @JonathanLeffler:你应该把它作为答案,因为它是值得的。
  • 或者像第二次一样在第一次尝试中使用unsigned char。 (我必须说你很好地隐藏了这种微妙的差异)。
  • 输出不应该是 0x00003039 和 0x7fff,那为什么不做 'for(i = sizeof(int) - 1; i >= 0; i--)'?
  • 感谢@JonathanLeffler 的回答。还是很模糊。为什么int 值在两种情况下都得到相同的输出?事实证明,short 在第一种情况下的值,它在第一次迭代cx[0] = ffffffff 中输出ffffffff(4 个字节)。我的论点是:cxchar*,所以当我们取消引用它时它应该给我们一个字节而不是四个,对吧?。

标签: c generics hex void-pointers


【解决方案1】:

对于第一种情况,改变:

printf("%.2x", cx[i]);

printf("%.2x", cx[i] & 0xFF);

普通的char 类型是有符号的,所以 0xFF 被符号扩展为一个全为 F 的 8 字节值,如打印输出所示。

第一个数字工作正常,因为所有字节都在 0x00..0x7F 范围内,因此该值没有转换为负整数——它保持正数。第二个数字不起作用,因为其中一个字节在 0x80..0xFF 范围内,因此被转换为负整数。 %.2x 将始终打印所有数字,但如果只有一个,则在该数字之前会有一个 0。 x 需要 unsigned int

使用printf() 和其他可变参数函数,参数列表的... 部分中的参数默认提升,因此char 类型(所有变体)被提升为intshort 也是如此) ,并且float 被提升为double

这在 C 标准 (ISO/IEC 9899-2011) 中有记录:

6.5.2.2 函数调用

6 如果表示被调用函数的表达式的类型不包含 原型,整数提升对每个参数执行,参数 将类型 float 提升为 double。这些被称为 default 参数 促销活动。

7 如果表示被调用函数的表达式具有包含原型的类型, 参数被隐式转换,就像通过赋值一样,转换为 对应的参数,取每个参数的类型为不合格版本 其声明的类型。函数原型声明器中的省略号表示 参数类型转换在最后一个声明的参数之后停止。默认参数 提升是在尾随参数上执行的。

8 没有隐式执行其他转换;尤其是数量和类型 参数不与函数定义中的参数进行比较 不包括函数原型声明符。


撇开半切线。

第 6 段的其余部分包括:

如果函数是用包含原型的类型定义的,并且 原型以省略号 (, ...) 或……结尾,行为未定义。

这句话必须在“如果表示被调用函数的表达式的类型不包含 原型,...'在段落的开头。这意味着如果您调用一个用省略号, ... 定义的函数,但在调用时范围内没有原型,则行为未定义。每当您调用可变参数函数时,您必须确保在范围内有一个原型。

【讨论】:

    猜你喜欢
    • 2014-12-24
    • 2014-10-12
    • 2014-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-31
    • 2018-06-24
    • 2018-11-13
    相关资源
    最近更新 更多