【问题标题】:How to initialize a double array with the precalculated hex values?如何使用预先计算的十六进制值初始化双精度数组?
【发布时间】:2017-05-20 03:40:57
【问题描述】:

我想实现浮点数数组的初始化。使用预先计算的十六进制值。结果与此类似:

double arr[3];
memcpy(&arr[0], "\xe3\x3b\xef\xf6\xc1\x78\xc6\x3f\xf9\x37\x5a\x8d\xfd\xae\x75\x3f\x62\xe9\x58\x48\x4f\x49\xc6\x3f",24);

我希望这样的初始化在一行中完成。就像在这个例子中一样(但在我的例子中是浮点数):

const char s[] = "\x48\x69\x21";

在语法上可能吗?

【问题讨论】:

  • 不,没有语法可以在定义点初始化对象的对象表示。
  • @KerrekSB:这不是太笼统了吗?
  • @Jarod42 - 不在 C 语言中它不会。它可能是一个陷阱值,或者是一个实现定义的值,但不是 UB。
  • C 或 C++。根据您使用的这两种不同编程语言中的哪一种,您的问题的答案会非常不同。
  • @SergeBallesta:如果您的环境不支持文件怎么办?实际的问题是为什么 OP 不想直接以doubles 的形式提供数据,但认为他必须通过char [] 绕道而行。这可能是一个 XY 问题。

标签: c++ arrays floating-point initialization hex


【解决方案1】:

更接近的是工会。问题是字符串litteral的最后一个字符为null,但这应该可以工作:

union {
    char chr[3 * sizeof(double) + 1];
    double arr[3];
} val = { "\xe3\x3b\xef\xf6\xc1\x78\xc6\x3f\xf9\x37\x5a"
    "\x8d\xfd\xae\x75\x3f\x62\xe9\x58\x48\x4f\x49\xc6\x3f" };

只是因为它使用了一个额外的字节,所以会浪费一些内存(通常在 32 位机器上是 4 个字节)


参考标准:

在 C 中,一个(非规范)注释说它应该在 6.5.2.3 结构和联合成员中工作

如果用于访问联合对象内容的成员与上次用于访问的成员不同 在对象中存储一个值,该值的对象表示的适当部分被重新解释 作为 6.2.6 中描述的新类型中的对象表示(有时称为“类型 双关语")

我找不到任何关于 C++ 的参考说明它是否被允许,但所有常见的编译器都接受它。我能找到的更相关的是

9.5 联合 [class.union]

在一个联合中,任何时候最多可以有一个非静态数据成员处于活动状态,即at的值 大多数非静态数据成员可以随时存储在联合中...联合对象的所有非静态数据成员都具有相同的地址。

这解释了为什么它可以工作

和:

3.10 左值和右值 [basic.lval]

§10 如果一个程序试图通过 glvalue 访问对象的存储值,而不是其中一个 以下类型的行为未定义... [未引用联合访问]

这清楚地表明它会导致未定义的行为。问题是相同的段落(称为严格别名规则)也存在于 C 6.5 Expressions §7...

TL/DR:联合方式在 C 中是明确有效的,在 C++ 中可能是 UB,所以我的建议是将它放在链接到 C++ 程序的 C 编译单元中。

【讨论】:

  • 问题是关于 C++,而不是 C。并且不允许通过 union 进行 C++ 类型双关的 AFAIK。
  • @Olaf:在某些情况下是允许的。其他用途是非标准的,最终以 UB 结尾,但实际上可能会按预期工作。
  • @AndyG 随着每个版本的发布,编译器以优化的名义利用 UB 变得更有创意。仅仅因为某件事可能今天有效,并不意味着它明天就会有效。
  • @Olaf 我说的是单独的编译单元,从未说过您可以在 C 和 C++ 源文件中使用相同的语法。但是我直接在 C++ 程序中使用 C 标准库中的函数,而我不能从 Python 或 Java 或 ...
【解决方案2】:

C++20 在 C++ 中带来了一种非常需要的非 UB 类型双关语。您现在可以执行以下操作。欢欣鼓舞。

double arr[] = {
    std::bit_cast<double>(0xE33BEFF6C178C63F),
    std::bit_cast<double>(0xF9375A8DFDAE753F),
    std::bit_cast<double>(0x62E958484F49C63F)
};

【讨论】:

    【解决方案3】:

    我建议使用hex floating-point literals 而不是位模式

    double arr[] =
    {
        -0x1.beff6c178c63fp564, // 0xE33BEFF6C178C63F
        -0x1.75a8dfdae753fp916, // 0xF9375A8DFDAE753F
        0x1.958484f49c63fp559,  // 0x62E958484F49C63F
    };
    

    【讨论】:

      猜你喜欢
      • 2014-11-13
      • 2016-02-01
      • 2013-11-11
      • 1970-01-01
      • 1970-01-01
      • 2014-02-07
      • 1970-01-01
      • 2013-05-02
      相关资源
      最近更新 更多