微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

指针转换产生奇怪的结果

如何解决指针转换产生奇怪的结果

我正在测试是否可以在同一数组中具有int和float值,我编写了以下代码

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

int main()

{
    int v[4]={0,0};
    *((float*)(&v[1]))=45.6;
    printf("%f\n",*((float*)(&v[1])));

    printf("%f\n",v[1]);
    return 0;



}

我原本期望45.599998和0或在两个printf上都具有相同的值,但是得到不同的结果: 45.599998 45.599983 为什么?,发生了什么事?

编辑
顺便说一句,我想强调的是,对于这个问题,我对替代方法的兴趣不大,而对理解为什么不起作用的兴趣更大。

解决方法

在示例代码中,如注释中指出的那样,调用undefined behavior。 (在这种情况下,我认为违反了strict aliasing。)

” [[是否可以在同一数组中包含intfloat值”

不在C中,任何array中的type只能包含一种类型。但是,如果这种安排的变体对您有用,则可以在compound type的单个实例中定义这两种类型,例如struct的数组。例如:

typedef struct {
   int iVal;
   float fVal;
} val_s;

val_s val[10];

现在,您拥有10类型的val_s个元素的数组,为此,每个元素都包含intfloat类型的成员。

C中复合类型的另一种变体(已在注释中向我指出,可能是您想要的更多),它是内置的C类型,它允许多种类型共享相同的内存是union。需要注意的是,由程序员来跟踪最后写入哪个成员,因为在给定的时间只有一个成员可以包含一个值...

示例:

typedef union {
   int iVal;
   float fVal;
} val_s;

val_s val;
,

我原本希望两个printf的值分别为45.599998和0或具有相同的值,但是得到的结果却不同:45.599998 45.599983为什么?发生了什么事?

假设我们使用此变体消除了代码中的一些未定义行为:

#include <string.h>
#include <stdio.h>

int main() {
    int v[4]={0,0};
    float f = 45.6;
    memcpy(&v[1],&f,sizeof f);

    printf("%f\n",f);
    printf("%f\n",v[1]);

    return 0;
}

这仍然具有未定义的行为,因为格式指令%fv[1]的类型不正确匹配,但是只要float不大于{{1} },并且int没有陷阱表示(对于大多数C实现而言,两者都适用)。

即使intf的值具有相同的字节序列表示形式,它们的类型之间的差异对于此代码也具有重要的影响。可变参数(例如v[1])的变量参数受“默认参数提升”的约束。它们使类型printf的值保持不变,但它们将int提升为类型float。因此,如果您的doublefloat在实践上通常有所不同,那么

    在两种情况下,即使仅考虑每个参数的字节序列,
  1. double也会收到不同的参数值,并且
  2. printf情况下,v[1]可能接收不到足够宽的值。

因此,如果您沉迷于在这种未定义行为的情况下假设程序实际执行的操作的可疑做法,那么更可能的可能性之一是在printf情况下它会查看字节v[1]的序列,再加上一些恰好位于内存中的随机字节,将它们解释为好像是float的字节,并根据运气和细节所选的测试值,其数值接近但不完全与您的double提升到的double匹配。

,

使用浮点说明符并传递一个整数值来满足格式字符串中的该参数是未定义行为,也就是说,所有选择均无效。

许多系统以完全不同的方式传递积分参数和浮点参数;有些没有。 “为什么”不能完全回答。您碰巧在一个其调用约定似乎没有不同地传递整数和浮点参数的系统上。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。