C

时间:2017-04-06 05:17:08

标签: c generics hex void-pointers

我试图在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");
    }
    

    在小端机器(Mac OSX)上按预期0x39300000案例输出int。对于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 scrollable : { direction : 'horizontal', directionLock : true },

1 个答案:

答案 0 :(得分:4)

对于第一种情况,请更改:

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

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

普通char类型已签名,因此0xFF符号扩展为所有F的8字节值,如打印输出中所示。

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

使用printf()和其他可变参数函数,参数列表的...部分中的参数是默认提升的,因此char类型(所有变量)被提升为{{1} }(按int),short被提升为float

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

  

6.5.2.2函数调用

     

6如果表示被调用函数的表达式具有不包含a的类型   原型,对每个参数执行整数提升,并对其进行参数化   将类型double提升为float。这些被称为默认参数   促销。 ......

     

7如果表示被调用函数的表达式具有包含原型的类型,   参数被隐式转换,就像通过赋值一样,转换为类型   相应的参数,将每个参数的类型作为不合格的版本   其声明的类型。函数原型声明符中的省略号表示法导致   参数类型转换在最后声明的参数后停止。默认参数   促销是在尾随参数上进行的。

     

8不会隐式执行其他转换;特别是,数量和类型   参数不与函数定义中的参数进行比较   不包含函数原型声明符。

半切向。

第6段的其余部分包括:

  

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

必须在'如果表示被调用函数的表达式具有不包含a的类型的上下文中读取该句子 原型,...'在段落的开头。这意味着如果您调用使用省略号, ...定义的函数,但在调用时范围内没有原型,则行为未定义。无论何时调用可变参数函数,都必须确保在范围内有原型。