简体   繁体   English

通过printf在c中打印负值

[英]Printing of negative value in c via printf

I am running a test code for learning C. However I am curious regarding representation of negative numbers n hexadecimal, for which I have written a test-code. 我正在运行用于学习C的测试代码。但是,我对以十六进制表示的负数n表示好奇,为此我编写了一个测试代码。 To my surprise, by running that test-code I am receiving only zero 令我惊讶的是,通过运行该测试代码,我只收到零

    union unin
    {
        char chrArray[4];
        float flotVal;
    }uninObj;

    uninObj.flotVal = -25;

    printf("%x %x %x %x",uninObj.chrArray[0], uninObj.chrArray[1], /
           uninObj.chrArray[2], uninObj.chrArray[3]);
    printf("\n Float in hex: %x",uninObj.flotVal);
    return 0;

Passing float to a specifier expecting unsigned int is undefined behaviour . float传递给期望unsigned int的说明符是未定义的行为

Furthermore, the unsigned int expected by %x is not guaranteed to be the same size as float . 此外,不能保证%x期望的unsigned intfloat相同。 So the attempt to trick printf that way may or may not "work". 因此,以这种方式欺骗printf的尝试可能会或可能不会“起作用”。

Anyway, for a variadic function such as printf the compiler will promote an argument of type float to double , so that may be the reason why you (and I) get 0 output. 无论如何,对于诸如printf之类的可变函数,编译器会将float类型的参数提升为double ,因此这可能就是您(和我)获得0输出的原因。

On my system 在我的系统上
sizeof(double) is 8 . sizeof(double)8
sizeof(unsigned int) is 4 . sizeof(unsigned int)4

And if you look at the bytes output for that part of the union , the first two are 0 . 并且,如果您查看该部分union的字节输出,则前两个为0 So having passed 8 bytes to the function instead of the 4 expected by %x , the data is aligned in a way that %x is getting four 0 value bytes. 因此,已将8个字节传递给函数而不是%x期望的4个字节,数据以%x获得四个0值字节的方式对齐。

On my CentOS 7 Intel 64 architecture, sizeof(float) is 4. So little endian result that I see on my test of 00 00 C8 C1 is a negative number. 在我的CentOS 7 Intel 64架构上,sizeof(float)为4。在测试00 00 C8 C1时看到的字节序太小了,是负数。 The Intel single precision floating point representation is: 英特尔单精度浮点表示法是:

1 bit sign
8 bit exponent
23 bit significand (with the first 1 bit implied)

As the Intel architecture is little-endian, the floating point value for 00 00 C8 C1 is 1100 0001 1100 1000 0000 0000 0000 0000 . 由于Intel体系结构为低端字节序,因此00 00 C8 C1的浮点值为1100 0001 1100 1000 0000 0000 0000 0000 The first 1 means the number is negative. 前1表示数字为负。 The next 8 bits, 10000011 (Decimal 131), are the exponent, and the next 4 bits 1001 , with the implied 1 bit 11001 , is the number 25 shifted right 4 bits. 接下来的8位10000011 (十进制131)是指数,接下来的4位1001 (含1位11001 )是将数字25右移4位。 The exponent of 131 is offset from 127 by 4, which is the number of bits that 1.1001 is shifted left to get back to 25. 131的指数从127偏移4,这是1.1001左移回到25的位数。

On a 64 bit representation, the exponent is 11 bits, and the exponent offset is 1023. So you would expect the number to be 1 (negative sign), Decimal 1027 in 11 bits 100 0000 0011 , then 25 decimal as 1001 with the implied leading 1 bit (as in the single precision version), then all zeroes which together is C0 39 00 00 , 00 00 00 00 . 在64位表示形式上,指数为11位,指数偏移为1023。因此,您希望数字为1(负号),以11位100 0000 0011十进制1027,然后以25十进制表示1001 。前导1位(如在单精度版本中),则所有零为C0 39 00 00 , 00 00 00 00 You can see that the last 4 bytes are all zeros. 您可以看到最后4个字节全为零。 But this is still little-endian, so as a 64 bit number it would look like 00 00 00 00 00 00 39 C0 . 但这仍然是低位字节序,因此作为64位数字,它看起来像00 00 00 00 00 00 39 C0 So you are getting all zeros if you print the first 4 bytes. 因此,如果打印前4个字节,则将得到全零。

You would see non-zero values from your program either by (a) Specifying an 8 character array in the declaration and printing all 8 (and you would see two bytes with 39 C0), or (b) using a value other than -25 in your test that requires more binary digits to represent like a large prime number or an irrational number (as suggested by @David C. Rankin). 您可以通过以下方法从程序中看到非零值:(a)在声明中指定8个字符的数组并打印所有8个字符(您将看到两个字节的39 C0),或者(b)使用非-25的值在您的测试中,需要更多的二进制数字来表示较大的质数或无理数(如@David C. Rankin所建议)。

Checking sizeof(float) would determine what your floating point size (in bytes) and I would expect you to see it as 8, because you are seeing zeroes and not C8 C1 like I do. 检查sizeof(float)将确定您的浮点大小(以字节为单位),并且我希望您将其视为8,因为您看到的是零而不是像我一样的C8 C1

First of all, this statement is flat-out wrong: 首先,此声明完全错误:

printf("\n Float in hex: %x",uninObj.flotVal);

%x expects its corresponding argument to be unsigned int , and passing an argument of a different type (as you do here) results in undefined behavior - the output could literally be anything. %x期望其对应的参数为unsigned int ,并且传递不同类型的参数(如此处所述)会导致未定义的行为-输出实际上可以是任何东西。

As of C99, you can use the %a or %A specifiers to print a hexadecimal representation of the floating-point value ( [+|-] x . xxxx ... , where each x is a hex digit). 作为C99的,则可以使用%a%A说明符打印浮点的十六进制表示( [+|-] x . xxxx ...其中每个x是一个十六进制数字)。 This is not the same thing as the value's binary representation in memory, though. 但是,这与值在内存中的二进制表示形式不同。

For the union, I'd suggest you use unsigned char for chrArray and use %hhx to print out each byte: 对于联合,我建议您为chrArray使用unsigned char ,并使用%hhx打印出每个字节:

union unin
{
    unsigned char chrArray[sizeof (float)];
    float flotVal;
}uninObj;

printf("%hhx %hhx %hhx %hhx",uninObj.chrArray[0], uninObj.chrArray[1], 
       uninObj.chrArray[2], uninObj.chrArray[3]);    

The hh length modifier in %hhx says that the corresponding argument has type unsigned char , rather than the unsigned int %x usually expects. %hhxhh长度修饰符表示相应的参数类型为unsigned char ,而不是%x通常期望的unsigned int类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM