错误:在 c 中转换用户定义的数据类型
Posted
技术标签:
【中文标题】错误:在 c 中转换用户定义的数据类型【英文标题】:Error : casting user defined data types in c 【发布时间】:2017-05-02 10:14:47 【问题描述】:这是我的问题的一个更简单的视图,我想将浮点值转换为定义的类型 v4si(我想使用 SIMD 操作进行优化。)请帮助将浮点/双精度值转换为定义的类型。
#include<stdio.h>
typedef double v4si __attribute__ ((vector_size (16)));
int main()
double stoptime=36000;
float x =0.5*stoptime;
float * temp = &x;
v4si a = ((v4si)x); // Error: Incompatible data types
v4si b;
v4si *c;
c = ((v4si*)&temp); // Copies address of temp,
b = *(c);
printf("%f\n" , b); // but printing (*c) crashes program
【问题讨论】:
C 还是 C++?哪一个? 有什么原因不能以正常方式使用内在函数吗?另外,我们在这里谈论的是什么 CPU/架构? x86?手臂 ?电源/PowerPC? 它的 C 编程(在标题中提到)。它的 x86 架构,实际上我是 SIMD 的新手,并试图通过使用 SIMD 向量乘法删除 for 循环来优化 c 代码。 好的 - 我已经更新了你的标签,并假设你想使用 SSE。如果您使用 *** 上的搜索工具,您会发现很多标记为[sse]
的问题 - 看看其中的一些问题,以熟悉使用 SIMD 内部函数的一些基础知识,
作为初学者,您可以更轻松地使用英特尔的 _mm_loadu_ps
内在函数来加载 4 个双精度,并使用 _mm_mul_ps
将它们相乘。与您使用的 GNU C 矢量扩展相比,英特尔的内在函数有更好的文档记录和更多的教程。主要的缺点是它们在 x86 之外不可移植,但您只针对 x86。请参阅 SSE 标签 wiki 以获取文档和教程的链接。
【参考方案1】:
您无需定义自定义 SIMD 向量类型 (v4si
) 或乱用强制转换和类型双关语 - 只需在适当的 *intrin.h
标头中使用提供的 intrinsics,例如
#include <xmmintrin.h> // use SSE intrinsics
int main(void)
__m128 v; // __m128 is the standard SSE vector type for 4 x float
float x, y, z, w;
v = _mm_set_ps(x, y, z, w);
// use intrinsic to set vector contents to x, y, z, w
// ...
return 0;
【讨论】:
同样的头文件也可以用于 AMD64 架构中的内部函数吗?我必须在多个系统上运行我的代码。 是的,没问题 - 如果您超越 SSE3,您需要了解您的目标架构支持哪些 SIMD 指令集,但您应该可以使用 SSE2/SSE3。 @Sarmad :如果您的目标是 64 位代码 (AMD64/x86-64),那么处理器支持 SSE 和 SSE2(默认情况下) - 所以是的,您可以使用xmmintrin.h
。当 AMD 为其芯片创建 64 位规范时,处理器支持 SSE/SSE2。英特尔随后采用了 AMD 规范,因此英特尔的所有 x86-64 处理器默认支持 SSE/SSE2。如果您需要 > SSE2,那么默认情况下并非所有 64 位处理器都支持这些功能。【参考方案2】:
您似乎在使用GCC vector extensions。下面的代码展示了如何使用向量扩展进行广播、向量+标量、向量*标量、加载和存储。 #包括
#if defined(__clang__)
typedef float v4sf __attribute__((ext_vector_type(4)));
#else
typedef float v4sf __attribute__ ((vector_size (16)));
#endif
void print_v4sf(v4sf a) for(int i=0; i<4; i++) printf("%f ", a[i]); puts("");
int main(void)
v4sf a;
//broadcast a scalar
a = ((v4sf) + 1)*3.14159f;
print_v4sf(a);
// vector + scalar
a += 3.14159f;
print_v4sf(a);
// vector*scalar
a *= 3.14159f;
print_v4sf(a);
//load from array
float data[] = 1, 2, 3, 4;
a = *(v4sf*)data;
//a = __builtin_ia32_loadups(data);
//store to array
float store[4];
*(v4sf*)store = a;
for(int i=0; i<4; i++) printf("%f ", store[i]); puts("");
Clang 4.0 和 ICC 17 支持 GCC 向量扩展的子集。但是,它们都不支持 GCC 支持的 vector + scalar
或 vector*scalar
操作。 Clang 的一种解决方法是使用 Clang 的 OpenCL 矢量扩展。我不知道 ICC 的解决方法。 MSVC 不支持我知道的任何类型的矢量扩展。
使用 GCC,即使它支持 vector + scalar
和 vector*scalar
,你也不能做到 vector = scalar
(但你可以使用 Clang 的 OpenCL 矢量扩展)。相反,您可以使用this trick。
a = ((v4sf) + 1)*3.14159f;
我会按照 Paul R 的建议去做,并使用与四种主要 C/C++ 编译器大致兼容的内部函数:GCC、Clang、ICC 和 MSVC。
下表列出了使用 GCC 的向量扩展和 Clang 的 OpenCL 向量扩展的每个编译器所支持的内容。
gcc g++ clang icc OpenCL
unary operations
[] yes yes yes yes yes
+, – yes yes yes yes yes
++, -- yes yes no no no
~ yes yes yes yes yes
! no yes no no yes
binary vector op vector
+,–,*,/,% yes yes yes yes yes
&,|,^ yes yes yes yes yes
>>,<< yes yes yes yes yes
==, !=, >, <, >=, <= yes yes yes yes yes
&&, || no yes no no yes
binary vector op scalar
+,–,*,/,% yes yes no no yes
&,|,^ yes yes no no yes
>>,<< yes yes no no yes
==, !=, >, <, >=, <= yes yes no no yes
&&, || no yes no no yes
assignment
vector = vector yes yes yes yes yes
vector = scalar no no no no yes
ternary operator
?: no yes no no ?
我们看到 Clang 和 ICC 不支持 GCC 的 vector operator scalar
操作。 C++ 模式下的 GCC 支持除 vector = scalar
之外的所有内容。 Clang 的 OpenCL 矢量扩展支持除三元运算符之外的所有内容。 Clang 的文档声称可以,但我没有让它工作。 C 模式下的 GCC 不支持二元逻辑运算符或三元运算符。
【讨论】:
请注意,g++ 比 gcc 支持更多的向量扩展(我应该知道,我实现了它们;-)。我认为甚至 gcc 也支持其中一些“不”,但我想我记错了。 @MarcGlisse,我更新了我的表格。我以Clang's table 为基础,这对于 GCC 来说显然是错误的。我现在测试测试了表中的许多操作。很高兴知道 GCC 支持 Clang 的 OpenCL 矢量扩展的所有内容,vector = scalar
和 vector.xyzw
表示法除外。也许是时候在 GCC 中修复 vector = scalar
了。为什么只有g++才支持逻辑运算符和三元运算符?
仅在 C++ 中支持的东西:与过去仅在 C 中支持几个向量扩展的原因相同,编写代码的志愿者对一种语言比另一种更感兴趣(2 个前端是在 gcc 中很大程度上是不相交的)。
@MarcGlisse,将 OpenCL swizzle 表示法 v.xyzw 作为 GCC 的一部分实现会很困难吗?你觉得有趣吗?我问了一个关于如何用 C++ 实现这个的问题***.com/questions/19923882/…
@MarcGlisse,Clang 不支持 ?:
,就像他们声称的 ***.com/questions/25345585/… 和 godbolt.org/g/rt67UM 一样。以上是关于错误:在 c 中转换用户定义的数据类型的主要内容,如果未能解决你的问题,请参考以下文章
SQL/C#:DataTable 到存储过程(从用户定义的表类型插入)- 转换错误