我早先使用过工会; 今天,当我读到这篇文章并开始知道这段代码时,我感到震惊
union ARGB
{
uint32_t colour;
struct componentsTag
{
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
} components;
} pixel;
pixel.colour = 0xff040201; // ARGB::colour is the active member from now on
// somewhere down the line, without any edit to pixel
if(pixel.components.a) // accessing the non-active member ARGB::components
Run Code Online (Sandbox Code Playgroud)
实际上是未定义的行为即从工会成员读取而不是最近编写的那个导致未定义的行为.如果这不是工会的预期用途,那是什么?有人可以详细解释一下吗?
更新:
事后我想澄清一些事情.
如果标准布局联合包含多个共享公共初始序列的标准布局结构,并且如果此标准布局联合类型的对象包含其中一个标准布局结构,则允许检查任何标准布局结构的公共初始序列.标准布局结构成员.§9.2/ 19:如果相应的成员具有布局兼容类型且两个成员都不是位字段,或者两者都是具有相同宽度的位字段,则一个或多个初始序列的两个标准布局结构共享一个公共初始序列成员.
C89/90在未指明的行为(附件J)中称之为,而K&R的书称其实施已定义.来自K&R的报价:
这是联合的目的 - 一个可以合法地保存几种类型中的任何一种的变量.[...]只要用法一致:检索到的类型必须是最近存储的类型.程序员有责任跟踪当前存储在联合中的类型; 如果将某些内容存储为一种类型并将其提取为另一种类型,则结果将依赖于实现. …
我的印象是访问union除最后一个成员之外的成员是UB,但我似乎无法找到一个可靠的参考(除了声称它是UB但没有标准支持的答案).
那么,这是不确定的行为?
这只是为了满足我自己的好奇心。
是否有此实现:
float InvSqrt (float x)
{
float xhalf = 0.5f*x;
int i = *(int*)&x;
i = 0x5f3759df - (i>>1);
x = *(float*)&i;
x = x*(1.5f - xhalf*x*x);
return x;
}
Run Code Online (Sandbox Code Playgroud)
在Rust中?如果存在,则发布代码。
我尝试过但失败了。我不知道如何使用整数格式编码浮点数。这是我的尝试:
fn main() {
println!("Hello, world!");
println!("sqrt1: {}, ",sqrt2(100f64));
}
fn sqrt1(x: f64) -> f64 {
x.sqrt()
}
fn sqrt2(x: f64) -> f64 {
let mut x = x;
let xhalf = 0.5*x;
let mut i = x as i64;
println!("sqrt1: {}, ", i);
i = 0x5f375a86 as …Run Code Online (Sandbox Code Playgroud) 我们最近在大学里开了一个关于多种语言编程特色的讲座.
讲师写下了以下功能:
inline u64 Swap_64(u64 x)
{
u64 tmp;
(*(u32*)&tmp) = Swap_32(*(((u32*)&x)+1));
(*(((u32*)&tmp)+1)) = Swap_32(*(u32*) &x);
return tmp;
}
Run Code Online (Sandbox Code Playgroud)
虽然我完全理解这在可读性方面也是非常差的风格,但他的主要观点是这部分代码在生产代码中运行良好,直到它们实现了高优化级别.然后,代码将什么都不做.
他说,变量的所有赋值tmp都将由编译器优化.但为什么会这样呢?
我知道有些情况下变量需要声明为volatile,这样编译器就不会触及它们,即使他认为它们永远不会被读或写,但我不知道为什么会发生这种情况.
我一直在使用isinf,isnan在Linux平台上运行完美的功能.但是这在OS-X上不起作用,所以我决定使用std::isinf std::isnan哪种适用于Linux和OS-X.
但英特尔编译器无法识别它,我猜它是英特尔编译器中的一个错误,根据http://software.intel.com/en-us/forums/showthread.php?t=64188
所以,现在我只是想避免麻烦和定义自己的isinf,isnan执行.
有谁知道如何做到这一点?
编辑:
我最终在我的源代码中进行了制作isinf/ isnan工作
#include <iostream>
#include <cmath>
#ifdef __INTEL_COMPILER
#include <mathimf.h>
#endif
int isnan_local(double x) {
#ifdef __INTEL_COMPILER
return isnan(x);
#else
return std::isnan(x);
#endif
}
int isinf_local(double x) {
#ifdef __INTEL_COMPILER
return isinf(x);
#else
return std::isinf(x);
#endif
}
int myChk(double a){
std::cerr<<"val is: "<<a <<"\t";
if(isnan_local(a))
std::cerr<<"program says isnan";
if(isinf_local(a))
std::cerr<<"program says isinf";
std::cerr<<"\n";
return 0;
}
int main(){
double a …Run Code Online (Sandbox Code Playgroud) 为什么这是一个警告?我认为在很多情况下使用multi-char int常量而不是"无意义"数字或者使用相同值定义const变量更为明确.解析wave/tiff /其他文件类型时,可以更清楚地将读取值与某些"EVAW","数据"等进行比较,而不是相应的值.
示例代码:
int waveHeader = 'EVAW';
Run Code Online (Sandbox Code Playgroud)
为什么这会发出警告?
假设我有floatIEEE 754 binary32的保证.给定一个与存储的有效浮点相对应的位模式std::uint32_t,如何float以最有效的标准兼容方式将其重新解释为?
float reinterpret_as_float(std::uint32_t ui) {
return /* apply sorcery to ui */;
}
Run Code Online (Sandbox Code Playgroud)
我有几种方法,我知道/怀疑/假设有一些问题:
通过reinterpret_cast,
float reinterpret_as_float(std::uint32_t ui) {
return reinterpret_cast<float&>(ui);
}
Run Code Online (Sandbox Code Playgroud)
或者等价的
float reinterpret_as_float(std::uint32_t ui) {
return *reinterpret_cast<float*>(&ui);
}
Run Code Online (Sandbox Code Playgroud)
哪个遭受别名问题.
通过union,
float reinterpret_as_float(std::uint32_t ui) {
union {
std::uint32_t ui;
float f;
} u = {ui};
return u.f;
}
Run Code Online (Sandbox Code Playgroud)
这实际上并不合法,因为它只允许从最近写的成员读取.然而,似乎有些编译器(gcc)允许这样做.
通过std::memcpy,
float reinterpret_as_float(std::uint32_t ui) {
float f;
std::memcpy(&f, &ui, 4);
return f;
}
Run Code Online (Sandbox Code Playgroud)
哪种AFAIK是合法的,但复制单个单词的函数调用似乎很浪费,尽管它可能会被优化掉.
通过reinterpret_cast …
c++ standards-compliance type-conversion language-lawyer c++11
下面的代码通过一些位攻击执行快速反平方根操作.该算法可能是由Silicon Graphics在1990年代早期开发的,它也出现在Quake 3中. 更多信息
但是我从GCC C++编译器收到以下警告:解除引用类型惩罚指针将破坏严格别名规则
我应该使用static_cast,reinterpret_cast还是dynamic_cast在这种情况下使用?
float InverseSquareRoot(float x)
{
float xhalf = 0.5f*x;
int32_t i = *(int32_t*)&x;
i = 0x5f3759df - (i>>1);
x = *(float*)&i;
x = x*(1.5f - xhalf*x*x);
return x;
}
Run Code Online (Sandbox Code Playgroud) c++ strict-aliasing gcc-warning undefined-behavior type-punning
union A{
int a;
int b;
};
int main(){
A u = {.a = 0};
int r = u.b; // #1 Is this UB?
}
Run Code Online (Sandbox Code Playgroud)
[class.union] 说
在联合中,如果非静态数据成员的名称引用其生命周期已开始且尚未结束的对象 ([basic.life]),则该非静态数据成员处于活动状态。联合类型对象的最多一个非静态数据成员在任一时刻可以是活动的,即任一时刻联合体中最多可以存储一个非静态数据成员的值。
在此示例中,仅A::a处于活动状态,然后 [basic.life] p7 表示
如果出现以下情况,则程序具有未定义的行为:
- 左值用于访问对象,或者
#1尝试访问生命周期尚未开始的对象。此访问是否会导致 UB,如果是,此要求是否过于严格?
顺便说一句,C 标准在此示例中是否提出了相同的要求?或者说,在这种情况下,C 有更宽松的要求吗?
在C标准中,我找到了一个注释,上面写着
如果用于读取联合对象内容的成员与最后用于在对象中存储值的成员不同,则该值的对象表示形式的适当部分将被重新解释为新类型中的对象表示形式,如下所述6.2.6(有时称为类型双关的过程)。这可能是非值表示。
这意味着它在 C 中是允许的。但是,https://eel.is/c++draft/diff.iso
除了上面列出的差异之外,子条款 [diff.iso] 按本文档的章节列出了 C++ 和 ISO C 之间的差异。
没有指出差异。
我的程序在该std::pow(double,int)函数中花费了90%的CPU时间.准确性不是这里的主要关注点,所以我想知道是否有更快的替代品.我想要尝试的一件事是铸造浮动,执行操作然后再加倍(尚未尝试过); 我担心这不是一种提高性能的可移植方式(不管大多数CPU本质上都是双重操作吗?)
干杯
c++ ×9
c ×5
type-punning ×3
unions ×2
c++11 ×1
casting ×1
endianness ×1
function ×1
gcc-warning ×1
math ×1
optimization ×1
performance ×1
portability ×1
rust ×1
sqrt ×1