具有印刷联合值的Quirk

时间:2016-04-05 18:52:51

标签: c printf unions

以下代码导致:

0.000000

10

在这种情况下从“数据”返回什么?我知道n.data.idatan.data.fdata将是正确的用法,我只是好奇为什么整数值在这种情况下有效,浮点值没有。

#include<stdio.h>
#include<stdlib.h>

typedef struct node
{
    union container
    {
        int idata;
        float fdata;
    } data;
    struct node *next;
} Node;

int main()
{
    Node i = {.data.idata = 10};
    Node n = {.data.fdata = 10.0};
    printf("%f\n", n.data);
    printf("%d\n", i.data);

    printf("\nExiting program...\n");
    return 0;
}

2 个答案:

答案 0 :(得分:4)

让我们暂时忽略明显的未定义行为,这是因为将不正确的类型传递给说明符$.when(1).then(function(data) { alert(data) })的printf函数。那种类型是一个匿名联盟。

Specifier <script src="https://code.jquery.com/jquery-git.js"> </script>假定从float到double的默认参数提升,在这种情况下不会发生,因为union f被传递给函数。因此该函数接收由{4}字节组成的联合f并表示一个浮点数,但尝试打印8个字节,因为它需要一个double。结果是无意义的值,在您的情况下为0.0。

(此答案假定为IEEE 754,而sizeof(int)&lt; = 4)

答案 1 :(得分:-2)

对我对错误问题的原始答案表示歉意。我想这个答案 可能有助于澄清那些接触这个问题的人谁是C新手2501正在谈论的(强调我的)

  

说明符f假定从float到double的默认参数提升,   哪个在这种情况下不会发生,因为传递了一个联合数据   功能。所以函数接收组成的联合数据   4个字节并表示一个浮点数,但尝试打印8个字节,因为   它预计会翻倍。结果是无意义的值,在您的情况下为0.0。

类型提升可以安全地或至少将一个二进制表示转换为另一个 以标准化的方式。以下内容全部在x86机器上完成。

无符号64位格式的10二进制值

  

| 0 1 0的 1 0000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000

二进制值10为32位浮点数...

  

| 00000000 | 00000000 | 00000的 1 00 | 1 00000 1 0

10位值为64位格式的双倍...

  

| 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00的 1 00 1 00 | 000000的 1 0

数字10的所有三个表示都有显着差异。类型促销 没有发生意味着printf语句中的数字被视为a 双,它是这样打印的。在这种情况下,它出现的唯一原因 零是精确的。

以下代码中的Node数据结构是8个字节。没有衬垫 在结构中或它不能是8个字节长。如果我们将float设置为10并next 到0我们在记忆中有这种表现......

  

| 00000000 | 00000000 | 00000的 1 00 | 1 00000 1 0 | 00000000 | 00000000 | 00000000 | 00000000

以上如果转换为双倍并打印printf("%f'\n");就可以了 看起来像0.0。如果您使用&#39; printf(&#34;%g \ n&#34;)&#39;你会看到一些 必须在8个字节中设置位,在我的情况下我得到了

5.39824e-315

要查看浮点类可以使用fpclassify的内容。请参阅下面的代码......

#include <assert.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct node {
  union container {
    float fdata;
    int idata;
  } data;
  uint32_t next;
} Node;

int main(void) {
  size_t nsize1 = sizeof(Node);
  assert(nsize1 == 8); 
  assert(sizeof(int)    == 4); 
  assert(sizeof(float)  == 4); 
  assert(sizeof(double) == 8); 
  Node  n   = {.data.fdata = 10.0};
  n.next = 0;
  double   d              = *(double*)&n;
  int    class_of_d       = fpclassify(d);
  assert(d > 0); 
  switch(class_of_d) {
    case FP_NAN        : printf("FP_NAN\n");break;
    case FP_INFINITE   : printf("FP_INFINITE\n");break;
    case FP_ZERO       : printf("FP_ZERO\n");break;
    case FP_NORMAL     : printf("FP_NORMAL\n");break;
    case FP_SUBNORMAL  : printf("FP_SUBNORMAL\n");break;
    case FP_SUPERNORMAL: printf("FP_SUPERNORMAL\n");break;
  }
  printf("%g\n", d); 
  return 0;
}