问题标签 [strict-aliasing]
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.
c++ - 使用用户数据的严格别名和回调
我有一个带有基于回调的 C API 的 c++ 库。回调类型如下所示:
用户可以像这样注册一个回调,并可以设置一个指向任意数据的指针,库将通过回调将该指针传回。
我主要关心的是:它是否违反了严格的别名规则?我需要将 userData 的类型更改为 char* 吗?
c++ - 基于通用 char[] 的存储并避免与严格混叠相关的 UB
我正在尝试构建一个类模板,它将一堆类型打包在一个适当大的 char 数组中,并允许将数据作为单独的正确类型引用进行访问。现在,根据标准,这可能会导致违反严格别名,从而导致未定义的行为,因为我们正在char[]
通过与其不兼容的对象访问数据。具体来说,标准规定:
如果程序尝试通过非下列类型之一的泛左值访问对象的存储值,则行为未定义:
- 对象的动态类型,
- 对象的动态类型的 cv 限定版本,
- 与对象的动态类型类似(如 4.4 中定义)的类型,
- 与对象的动态类型相对应的有符号或无符号类型,
- 对应于对象动态类型的 cv 限定版本的有符号或无符号类型,
- 聚合或联合类型,在其元素或非静态数据成员中包括上述类型之一(递归地包括子聚合或包含联合的元素或非静态数据成员),
- 一个类型,它是对象的动态类型的(可能是 cv 限定的)基类类型,
- 一个
char
或unsigned char
类型。
鉴于突出显示的要点的措辞,我提出了以下alias_cast
想法:
(上面的测试代码,尤其是Data
class只是一个简单的想法演示,所以请不要指出我应该如何使用std::pair
or std::tuple
。alias_cast
模板还应该扩展为处理 cv 限定类型,它只能是安全的在满足对齐要求时使用,但我希望这个片段足以证明这个想法。)
这个技巧消除了 g++ 的警告(使用 编译时g++ -std=c++11 -Wall -Wextra -O2 -fstrict-aliasing -Wstrict-aliasing
),并且代码可以工作,但这真的是告诉编译器跳过基于严格别名的优化的有效方法吗?
如果它无效,那么如何在不违反别名规则的情况下实现这样的基于 char 数组的通用存储类?
编辑:用这样alias_cast
的简单替换reinterpret_cast
:
使用 g++ 编译时会产生以下警告:
aliastest-so-1.cpp:在 'T& Data::first() 的实例化中 [with T = int; U = short unsigned int]': aliastest-so-1.cpp:28:16:
这里需要 aliastest-so-1.cpp:21:58: 警告:取消引用类型双关指针将破坏严格别名规则 [-严格锯齿]
c++ - 释放/删除联合 malloc/C/C++ 中的新数组
我正在工作并且正在考虑使用工会。我决定反对它,因为设计确实需要一个结构/类,但它最终导致了以下假设性问题:
假设你有一个像这个人为的例子这样的联合:
. . . 然后你分配一个数组并尝试从其他地方删除它:
我认为这会起作用,尽管它在技术上没有定义,因为 malloc 的实现方式。我还假设它在分配 array_c 时会起作用,尽管与 int 与 float 不同,数组的大小不太可能相同。
可以使用类似的 new 和 delete 重复测试。我猜这些也行得通。
我猜语言规范会讨厌我这样做,但我希望它会起作用。它让我想起了“即使它是数组而不是对象,也不要删除转换为 void* 的新指针”业务。
所以问题是:规范对这样做有什么看法?我简单地检查了一下,但找不到任何特别解决这种情况的东西。无论如何,这是多么不明智——从功能的角度来看(我意识到从清晰的角度来看这很糟糕)。
这纯粹是出于迂腐目的的好奇问题。
c++ - C ++中联合中的两个数组
是否可以像这样在联合中共享两个数组:
这两个数组共享相同的内存大小还是其中一个更长?
c++ - 联合:从联合的一个数据成员中读取以写入另一个
我知道对于下面的代码,下面的“非法”是未定义的(虽然一些编译器允许它),因为联合成员“a”是活动的,然后我们从联合成员“b”中读取。问题是,“AmILegal”中的代码是否修复了它,还是我在做一些可怕甚至更晦涩的事情?我可以使用 memcpy 来实现相同的效果,还是我在那里调用了另一个未定义的行为?
编辑:也许这个例子不够清楚。我想做的就是激活另一个成员。所以我将浮点数更改为int。虽然看起来很傻,但更接近真实案例。阅读下面的代码。
(是否出于某种原因不允许将一个工会成员复制到另一个工会成员中?)
如果以上所有内容听起来都不是很有用,请认为 a 实际上是一个与 float[4] 结合的 _m128。位表示始终是准确和正确的。在某个时间点,您将需要实际使用它,并且您需要将它作为浮点数组放在主内存中。“复制指令”实际上是从 _m128 联合成员到 float[4] 成员的 _mm_store_ps。因此,关于 memset 的问题 - 也许这是我需要的更准确的例子......
c - 通过示例了解限制限定符
关键字的restrict
行为在 C99 中由 6.7.3.1 定义:
令 D 是一个普通标识符的声明,它提供了一种将对象 P 指定为指向类型 T 的限制限定指针的方法。
如果 D 出现在一个块内并且没有存储类 extern,则让 B 表示该块。如果 D 出现在函数定义的参数声明列表中,则让 B 表示关联的块。否则,让 B 表示 main 块(或在独立环境中程序启动时调用的任何函数块)。
在下文中,如果(在对 E 求值之前执行 B 的某个序列点)修改 P 以指向它以前指向的数组对象的副本,则称指针表达式 E 基于对象 P将改变 E.119 的值)请注意,“基于”仅针对具有指针类型的表达式定义。
在每次执行 B 期间,令 L 为基于 P 具有 &L 的任何左值。如果 L 用于访问它指定的对象 X 的值,并且 X 也被修改(通过任何方式),则适用以下要求: T 不应是 const 限定的。用于访问 X 值的每个其他左值也应具有基于 P 的地址。就本子条款而言,修改 X 的每个访问也应视为修改 P。如果为 P 分配了一个指针表达式 E 的值,该指针表达式 E 基于与块 B2 关联的另一个受限指针对象 P2,则 B2 的执行应在 B 的执行之前开始,或者 B2 的执行应在任务。如果不满足这些要求,则行为未定义。
和其他人一样,我很难理解这个定义的所有复杂性。作为对这个问题的回答,对于第 4 段中的每个要求,我希望看到一组很好的示例,说明会违反要求的用法。本文:
用“编译器可能假设......”的方式很好地呈现规则;扩展该模式并结合编译器可以做出的假设,以及它们如何无法保持,每个示例都会很棒。
c - 混淆调整代码以使用限制限定符
我正在尝试调整以下版本的stpcpy
函数以使用restrict
-qualified 指针作为其参数和内部,但我不确定简单地添加限定符是否会导致引入未定义的行为。
假设 C99 6.7.3.1 中关于访问对象的规则仅适用于访问的单个对象而不是整个数组,我认为这可能没问题,因为写入的元素只能访问一次,并且只能用于写入。但我restrict
在这一点上使用起来很不舒服,不想仅仅依靠我自己的判断。
c++ - 这个联合会破坏严格的别名吗?浮点寄存器呢
我必须使用那个联合来实现一点 IEEE 技巧,这会破坏严格的混叠吗?GCC 没有发出任何警告(使用 GCC 4.5 和 4.6 进行了尝试,即使使用了迂腐的严格别名,但据我所知,GCC 并不能很好地捕捉严格的别名规则违规行为(大量误报/误报)。
那是我目前正在使用的片段,它似乎可以正常工作而没有任何警告,但某些编译器优化可能会出现副作用或未定义的行为。因此,如果那段代码在某些情况下可能不安全,我将努力将其删除。
此外,我假设这段代码需要将数据从标准寄存器移动到大多数现代 CPU 上的浮点寄存器(只是对此感到好奇),这涉及到与旧 CPU 相关的一些额外周期,对吗?
上面的代码不打算做优化,所以不要贬低我滥用优化,上面的代码是我获得某个结果的最简单方法(幸运的是,最简单的方法似乎也是最快的我的情况!),如果结果不安全,那么我将使用较慢的方法。
提前致谢
c - 关于指向 char 的通用指针和严格的别名
我不知道为什么下面的代码工作正常,没有gcc
错误(-fstrict-aliasing -Wstrict-aliasing=1
)。
如果我遵循严格的别名规则:
n1570, § 6.5 表达式
对象的存储值只能由具有以下类型之一的左值表达式访问:
— 与对象的有效类型兼容的类型,
— 与对象的有效类型兼容的类型的限定版本,
— 与对象的有效类型相对应的有符号或无符号类型,
— 对应于对象有效类型的限定版本的有符号或无符号类型,
— 在其成员中包含上述类型之一的聚合或联合类型(递归地,包括子聚合或包含联合的成员),或
— 一种字符类型。
但*q
不具有与 兼容的类型*p
,要么是限定版本,要么是对应的有符号或无符号类型,要么是字符类型。
那么,为什么允许呢?
c++ - 允许将 T* 与 char* 混淆。是否也允许反过来?
注意:此问题已被重命名并简化,以使其更具针对性和可读性。大多数评论都引用了旧文本。
根据标准,不同类型的对象可能不会共享相同的内存位置。所以这是不合法的:
然而,该标准允许这条规则有一个例外:任何对象都可以通过指向char
or的指针来访问unsigned char
:
但是,我不清楚这是否也允许反过来。例如: