VS2019,发布,x86.
template <int i> float get() const {
int f = _mm_extract_ps(fmm, i);
return (float const&)f;
}
Run Code Online (Sandbox Code Playgroud)
使用return (float&)f;编译器时使用
extractps m32, ...
movss xmm0, m32
Run Code Online (Sandbox Code Playgroud)
.正确的结果
使用return (float const&)f;编译器时使用
extractps eax, ...
movd xmm0, eax
Run Code Online (Sandbox Code Playgroud)
.错误的结果
T&和T const&首先是T然后是const的主要思想.Const只是程序员的某种协议.你知道你可以解决它.但汇编代码中没有任何const,但是类型为float IS.我认为对于float和float const而言它必须是汇编中的浮点表示(cpu寄存器).我们可以使用中间int reg32,但最终解释必须是float.
而此时它看起来像回归,因为这之前工作正常.并且在这种情况下使用float也绝对是奇怪的,因为我们不应该考虑浮动const和安全性而是浮动的临时变量并且确实值得怀疑.
微软回答:
嗨Truthfinder,感谢自成一体的复制品.碰巧,这种行为实际上是正确的.正如我的同事@Xiang Fan [MSFT]在内部电子邮件中所述:
由[a c-style cast]执行的转换尝试以下序列:(4.1) - const_cast(7.6.1.11),(4.2) - static_cast(7.6.1.9),(4.3) - static_cast后跟const_cast ,(4.4) - reinterpret_cast(7.6.1.10)或(4.5) - reinterpret_cast后跟const_cast,
如果转换可以用上面列出的多种方式解释,则使用列表中首先出现的解释.
所以在你的情况下,(const float&)被转换为static_cast,其效果是"初始化表达式被隐式转换为类型为"cv1 T1"的prvalue.应用临时实现转换并将引用绑定到结果".
但在另一种情况下,(float&)被转换为reinterpret_cast,因为static_cast无效,这与reinterpret_cast(&operand)相同.
您正在观察的实际"错误"是一个强制转换:"将浮点型值"1.0"转换为等效的int-typed值"1"",而另一个强制转换说"将1.0的位表示形式转换为一个浮点数,然后将这些位解释为int".
出于这个原因,我们建议不要使用c风格的演员表.
谢谢!
MS论坛链接:https://developercommunity.visualstudio.com/content/problem/411552/extract-ps-intrinsics-bug.html
有任何想法吗?
PS我真正想要的是什么:
float val …Run Code Online (Sandbox Code Playgroud) 在下面的问题中:
什么是将一个浮点数类型化为int的正确方法,反之亦然?,结论是从整数位构造双精度的方法,反之亦然memcpy.
那很好,pseudo_cast转换方法有:
template <typename T, typename U>
inline T pseudo_cast(const U &x)
{
static_assert(sizeof(T) == sizeof(U));
T to;
std::memcpy(&to, &x, sizeof(T));
return to;
}
Run Code Online (Sandbox Code Playgroud)
我会像这样使用它:
int main(){
static_assert(std::numeric_limits<double>::is_iec559);
static_assert(sizeof(double)==sizeof(std::uint64_t));
std::uint64_t someMem = 4614253070214989087ULL;
std::cout << pseudo_cast<double>(someMem) << std::endl; // 3.14
}
Run Code Online (Sandbox Code Playgroud)
我只是阅读标准和cppreference的解释是,也应该可以用来就地memmove改变有效类型,如下所示:
template <typename T, typename U>
inline T& pseudo_cast_inplace(U& x)
{
static_assert(sizeof(T) == sizeof(U));
T* toP = reinterpret_cast<T*>(&x);
std::memmove(toP, &x, sizeof(T));
return *toP;
}
template <typename T, typename U> …Run Code Online (Sandbox Code Playgroud) 我目前正在从事一个项目,其中提供了以下结构。我的工作是 C++,但该项目同时使用 C 和 C++。C 和 C++ 都使用相同的结构定义。
typedef struct PacketHeader {
//Byte 0
uint8_t bRes :4;
uint8_t bEmpty :1;
uint8_t bWait :1;
uint8_t bErr :1;
uint8_t bEnable :1;
//Byte 1
uint8_t bInst :4;
uint8_t bCount :3;
uint8_t bRres :1;
//Bytes 2, 3
union {
uint16_t wId; /* Needed for Endian swapping */
struct{
uint16_t wMake :4;
uint16_t wMod :12;
};
};
} PacketHeader;
Run Code Online (Sandbox Code Playgroud)
根据结构实例的使用方式,结构所需的字节序可以是大端或小端。由于结构的前两个字节都是单个字节,因此当字节序更改时不需要更改这些字节。字节 2 和 3 存储为单个uint16_t,是我们需要交换以实现所需字节顺序的唯一字节。为了实现字节序交换,我们一直在执行以下操作:
//Returns a constructed instance of PacketHeader with relevant fields …Run Code Online (Sandbox Code Playgroud) 我是C++的新手,有以下内容,让我们称之为问题.在我的计算机模拟中,我使用矢量工作了很多.我自己构建了一个表示向量的小结构,并希望学习如何进行操作(例如normalize()函数更有效.另外,使用C++有什么好处valarray吗?似乎有一些有用的方法预先实现.
我差点专门用 normalize()向量函数和加法/减法/乘法.由于我的所有向量只有三个元素,我对在项目中包含第三方库犹豫不决.
这是我的结构:
struct vector_t {
int _i, _j, _k;
vector_t(int i, int j, int k) {
_i = i;
_j = j;
_k = k;
}
vector_t() {}
inline int getI() {
return _i;
}
inline int getJ() {
return _j;
}
inline int getK() {
return _k;
}
inline void setI(int val) {
_i = val;
}
inline void setJ(int val) {
_j = val;
}
inline void setK(int val) {
_k …Run Code Online (Sandbox Code Playgroud) 我从网络接收缓冲区,该缓冲区被转换为32位字的数组.我有一个单词被我的界面文档定义为ieee float.我需要从缓冲区中提取这个单词.在不调用转换的情况下从一种类型转换为另一种类型很困难.这些位已经符合ieee浮点标准,我不想重新排列任何位.
我的第一次尝试是将地址转换uint32_t为a void*,然后将其转换void*为a float*,然后取消引用为float:
float ieee_float(uint32_t f)
{
return *((float*)((void*)(&f)));
}
Run Code Online (Sandbox Code Playgroud)
错误:解除引用类型惩罚指针将破坏严格别名规则[-Werror = strict-aliasing]
我的第二次尝试是这样的:
float ieee_float(uint32_t f)
{
union int_float{
uint32_t i;
float f;
} tofloat;
tofloat.i = f;
return tofloat.f;
}
Run Code Online (Sandbox Code Playgroud)
然而,街上的一句话是,工会完全不安全.从最近没有编写的联合成员读取它是未定义的行为.
所以我尝试了更多的C++方法:
float ieee_float(uint32_t f)
{
return *reinterpret_cast<float*>(&f);
}
Run Code Online (Sandbox Code Playgroud)
错误:解除引用类型惩罚指针将破坏严格别名规则[-Werror = strict-aliasing]
我的下一个想法是"搞砸它.为什么我要处理指针呢?" 并尝试过:
float ieee_float(uint32_t f)
{
return reinterpret_cast<float>(f);
}
Run Code Online (Sandbox Code Playgroud)
错误:从'uint32_t {aka unsigned int}'类型无效转换为'float'类型
有没有办法在不触发警告/错误的情况下进行转换?我用g ++编译-Wall -Werror.我宁愿不接触编译器设置.
我标记了C,因为c解决方案是可以接受的.
uint32_t Seed() {
uint64_t seed = GetSomeReasonable64BitIntegerSeed();
return *(uint32_t*)&seed ^ *((uint32_t*)&seed + 1);
}
Run Code Online (Sandbox Code Playgroud)
上面不是真正的代码,但这基本上是真正的代码所做的.我从g ++那里得到一个警告,它违反了严格的别名,谷歌搜索它,好吧我想解决它.我发现了这个问题,但它没有提供一个明确的解决方案,除了使用memcpy或依赖于未定义但实际上没有问题的行为,即访问联合的未设置成员.
我能想到的当前选择是,
memcpy.union并将此部分编译为C,其中语言标准允许通过联合进行类型惩罚.什么是在字节数组中分配一个double到8个字节的快速方法?
我有一个大约4k字节的字节数组,我试图从中取出8个字节并将其复制到一个double中.我试图避免memmove和memcpy出于速度原因,因为分配变量要快得多.我在嵌入式世界工作,任何其他快速实现都受到赞赏.
void foo(double *pdest)
{
// Try 1: I am using 1 element in the array, it won't work
*pdest = (double)p->stk[stkpos];
// Try 2: I am attempting to loose the single element element
*pdest = (double)((double*)&p->stk[stkpos]);
}
Run Code Online (Sandbox Code Playgroud)
这两种解决方案都没有对我有用,我不确定如何实现这一目标.
c++ ×6
type-punning ×2
assembly ×1
c ×1
casting ×1
double ×1
embedded ×1
intrinsics ×1
sse ×1
struct ×1
unions ×1
vector ×1
visual-c++ ×1