错误:在 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 + scalarvector*scalar 操作。 Clang 的一种解决方法是使用 Clang 的 OpenCL 矢量扩展。我不知道 ICC 的解决方法。 MSVC 不支持我知道的任何类型的矢量扩展。

使用 GCC,即使它支持 vector + scalarvector*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 = scalarvector.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 到存储过程(从用户定义的表类型插入)- 转换错误

C语言自定义数据类型

C#中string类型转换为自定义数据类型怎么转?

c语言的基本数据类型都有啥,麻烦知道用大括号分类,非常感谢

SQL SERVER中强制类型转换cast和convert的区别

关于C语言数据类型转换的一个小问题,很简单哦!!