问题标签 [type-punning]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
11 回答
249065 浏览

c++ - 什么是严格的别名规则?

当询问C 中常见的未定义行为时,人们有时会提到严格的别名规则。
他们在说什么?

0 投票
5 回答
3659 浏览

c - 在 C 中安全地把 char* 加倍

在我编写的开源程序中,我正在从文件中读取二进制数据(由另一个程序编写)并输出整数、双精度和其他各种数据类型。挑战之一是它需要在两种字节序的 32 位和 64 位机器上运行,这意味着我最终不得不做相当多的低级位旋转。我对类型双关语和严格别名了解(非常)一点,并希望确保我以正确的方式做事。

基本上,很容易从 char* 转换为各种大小的 int:

我有一组支持函数来根据需要交换字节顺序,例如:

在运行时,程序会检测机器的字节序并将上述之一分配给函数指针:

现在,当我尝试将 char* 转换为 double 时,棘手的部分就来了。我想像这样重新使用字节序交换代码:

然而,一些编译器可能会优化掉“int64todouble.i”赋值并破坏程序。有没有更安全的方法来做到这一点,同时考虑到这个程序必须保持性能优化,而且我不希望编写一组并行转换来直接将 char* 转换为 double ?如果双关语的联合方法是安全的,我是否应该重写我的函数,如 snativeint64_t 来使用它?


我最终使用了Steve Jessop 的答案,因为转换函数被重写为使用 memcpy,如下所示:

编译成与我的原始代码完全相同的汇编程序:

在这两者中,memcpy 版本更明确地表达了我正在尝试做的事情,并且应该适用于即使是最天真的编译器。

亚当,你的回答也很棒,我从中学到了很多。感谢您的发布!

0 投票
4 回答
9867 浏览

c++ - 对 C++ 中的类型双关有何看法?

我对 C++ 中类型双关语指针/数组的约定很好奇。这是我目前的用例:

通过将二进制数据块视为 32 位整数数组(我们知道它的总长度是 4 的倍数),然后对所有值求和并忽略溢出,计算一个简单的 32 位校验和。

我希望这样的函数看起来像这样:

现在我的问题是,您认为转换data为的“最佳”方式是udata什么?

C风格的演员?

假设所有指针都是可转换的 C++ 强制转换?

C++ 在任意指针类型之间使用中间转换void*

通过工会铸造?

我完全意识到这不是一个 100% 可移植的解决方案,但我只希望在我知道它可以工作的一小部分平台上使用它(即未对齐的内存访问和编译器对指针别名的假设)。你会推荐什么?

0 投票
5 回答
373 浏览

c - 从字节内联重新组装浮点数

我在 PIC32MX 系列微处理器上使用 HiTech PICC32,但我认为这个问题对于任何熟悉 C 语言的人来说已经足够普遍了。(这几乎等同于 C90,sizeof(int) = sizeof(long) = sizeof(float ) = 4.)

假设我读取了一个 4 字节的数据字,它代表float. 我可以使用以下方法快速将其转换为实际的浮点值:

但这仅适用于左值。例如,我不能在函数返回值上使用它,例如:

是否有一种简短而甜蜜的方式来内联,即没有函数调用或临时变量?老实说,我没有理由避免函数调用或额外的 var,但这让我很烦恼。一定有我想念的方法。

补充:我没有意识到这WORD实际上是一个常见的 typedef。我更改了宏参数的名称以避免混淆。

0 投票
2 回答
2537 浏览

java - Java:在原始数组上使用类型双关语?

我需要能够将字节数组转换为其他原始类型数组/从其他原始类型数组转换,但我需要类型 punning而不是强制转换。没有强制转换的原始副本的正确术语?

我认为可以执行以下操作:

不幸的是,似乎bb.asIntBuffer()不是通过“按位”或“原始”复制内容来创建新的 IntBuffer,而是在现有 ByteBuffer 上创建新的“视图” 这就是为什么.array()打算失败。

我浏览了 JDK 的源代码,发现了一些类,所有这些缓冲区类都使用这些类并且可以做我需要的东西,但是是内部的(例如 class Unsafe)。

虽然我认为可以通过将字节缓冲区包装在一些中ObjectInputStream并通过读取原始值来实现我的目标.readInt(),但我认为这将是一个混乱且缓慢的解决方法。

那么,如果不进行神奇的原始类型算术(移位、检查字节序……),还有其他可能的解决方案吗?

注意:我需要两个方向:byte[12] -> int[3] 和 int[3] -> byte[12]

0 投票
16 回答
133806 浏览

c++ - C 和 C++ 中联合的用途

我之前很舒服地使用了工会;今天当我看到这篇文章并知道这段代码时我很震惊

实际上是未定义的行为,即从最近写入的联合成员之外的成员读取会导致未定义的行为。如果这不是联合的预期用途,那是什么?有人可以详细解释一下吗?

更新:

我想在事后澄清一些事情。

  • 对于 C 和 C++,这个问题的答案是不一样的。我无知的年轻自我将其标记为 C 和 C++。
  • 在浏览了 C++11 的标准之后,我不能确定地说它调用访问/检查非活动联合成员是未定义/未指定/实现定义的。我只能找到§9.5/1:

    如果标准布局联合包含多个共享公共初始序列的标准布局结构,并且此标准布局联合类型的对象包含标准布局结构之一,则允许检查任何标准布局的公共初始序列标准布局结构成员。§9.2/19:两个标准布局结构共享一个共同的初始序列,如果相应的成员具有布局兼容的类型,并且两个成员都不是位域或两者都是一个或多个初始序列的具有相同宽度的位域成员。

  • 在 C 语言中(C99 TC3 - DR 283起)这样做是合法的(感谢 Pascal Cuoq提出这个问题)。但是,如果读取的值恰好对于它所读取的类型无效(所谓的“陷阱表示”),那么尝试这样做仍然会导致未定义的行为。否则,读取的值是实现定义的。
  • C89/90 在未指定的行为(附件 J)下指出了这一点,K&R 的书说它是定义的实现。来自 K&R 的报价:

    这就是联合的​​目的——一个可以合法地持有几种类型中的任何一种的单一变量。[...] 只要用法一致:检索到的类型必须是最近存储的类型。程序员有责任跟踪当前存储在联合中的类型;如果将某些内容存储为一种类型并提取为另一种类型,则结果取决于实现。

  • 摘自 Stroustrup 的 TC++PL(重点是我的)

    联合的使用对于数据的兼容性可能是必不可少的 [...]有时误用于“类型转换”。

最重要的是,提出这个问题(自我问起,其标题保持不变)的目的是了解联合的目的,而不是标准允许的内容。例如,C++ 标准当然允许使用继承进行代码重用,但是这不是将继承作为 C++ 语言特性引入的目的或初衷。这就是安德烈的答案继续被接受的原因。

0 投票
1 回答
376 浏览

c - 编译时浮动包装/双关语

我正在为 PIC32MX 编写 C,使用 Microchip 的 PIC32 C 编译器(基于 GCC 3.4)编译。

添加了我遵循的标准是 GNU99(带有 GNU 扩展的 C99,编译器标志-std=gnu99

我的问题是:我有一些可重新编程的数字数据存储在 EEPROM 或芯片的程序闪存中。这意味着当我想存储一个浮点数时,我必须做一些类型双关语:

我还将默认值包含为编译时间常量数组。对于(无符号)整数值,这很简单,我只使用整数文字。但是,对于浮点数,我必须使用这个 Python 片段将它们转换为它们的单词表示,以将它们包含在数组中:

...因此我的默认值数组具有这些难以理解的值,例如:

(这些实际上采用X 宏构造的形式,但这在这里没有什么区别。)注释很好,但有更好的方法吗?能够做类似的事情真是太好了:

...但我完全不知所措,我什至不知道这样的事情是否可能。

笔记

  1. 显然,“不,这不可能”是一个可以接受的答案,如果是真的。
  2. 我不太关心可移植性,所以实现定义的行为很好,未定义的行为不是(我面前有 IDB 附录)。
  3. 据我所知,这需要进行编译时转换,因为DEFAULTS它在全局范围内。如果我对此有误,请纠正我。
0 投票
5 回答
823 浏览

c++ - 严格的指针别名:针对特定问题的任何解决方案?

我有一个由违反严格的指针别名规则引起的问题。我有一个T来自模板的类型和一些Int相同大小的整数类型(如sizeof)。我的代码基本上执行以下操作:

因为T是一些可以具有构造函数的任意(除了大小限制)类型,所以我不能将Tand合并Int。(这仅在 C++0x 中允许,甚至 GCC 还不支持)。

有什么办法可以重写上述伪代码以保留功能并避免破坏严格的别名规则?请注意,这是一个模板,我无法控制T; some_other_t赋值和随后的比较确实发生在模板代码中。

T(作为记录,如果包含任何位字段,上述代码在 GCC 4.5 上开始中断。)

0 投票
2 回答
1525 浏览

c++ - 严格的指针别名:通过“易失性”指针/引用访问是一种解决方案吗?

特定问题、自我回答和评论之后,我想了解它是否是正确的解决方案、解决方法/黑客或完全错误。

具体来说,我重写了代码:

作为:

带有volatile指针的限定符。

让我们假设在我的情况下对待Tint有道理的。这种通过volatile引用访问是否解决了指针别名问题?

作为参考,来自规范:

[注意: volatile 是对实现的提示,以避免涉及对象的激进优化,因为对象的值可能会通过实现无法检测到的方式进行更改。详细语义见 1.9。一般来说,volatile 的语义在 C++ 中与在 C 中的语义相同。 — 尾注]

编辑:

上面的代码至少在 GCC 4.5 上确实解决了我的问题。

0 投票
1 回答
1214 浏览

c - 冗余 __packed__ 属性

此代码适用于 Microchip 的 PIC32MX 微处理器。他们的编译器本质上是 GCC 3.4。

我倾向于使用 GCC 的__packed__属性将位域打包到一个联合中,然后将它们检索为unsigned char(即类型双关语)以通过 SPI 或 I2C 发送。这种行为都是由我的实现定义的,并且运行良好。我更喜欢这个而不是一百行左右的掩蔽和移位:)

我的问题是:__packed__下面的代码中是否有多余的属性?乍一看,我认为工会高层成员可以免去,但我不太确定。或者我可以省略嵌套结构中的那些吗?