opencl:C++11下使用别名(x,y,z,hi,lo...)访问vector类型(cl_int2,cl_long16...)的元素
来源:互联网 发布:重庆seo服务 编辑:程序博客网 时间:2024/06/02 00:52
在gcc(5.2.0)下使用C++11写opencl的主机端代码时,发现无法像内核代码一样对cl_int2
这样的向量(vector)类型用pos.x,pos.y
这样的别名来访问向量元素,只能用pos.s[0]
这种数组访问的方式。这是为什么?
这本是个小问题,但本人是个完美主义者,总想搞个清楚,最后总算搞清楚了,于是就有了本文。
这是
platform.h
中cl_int2
的定义,可以看出,虽然代码中有,x,y名字定义,但编译开关__CL_HAS_ANON_STRUCT__
导致这部分代码是灰的/无效的
opencl内核代码中向量元素的访问
在opencl内核代码中,对于opencl中的向量类型,既可以使用s0~sF(根据向量长度不同)来访问向量中的指定元素,也可以用元素的别名来访问(x,y,z,w,hi,lo…)
比如向量数据float4
,是由4个float
组成的向量
float4 f;float s0=f.s0; //f中第一个元素float s0=f.x; //与前一行等价float2 f2=f.hi //f中前2个元素组成的float2
可以看出,使用x,y,hi,lo这样的别名,代码更加直观易懂。
opencl主机端向量类型的定义
这些向量类型在主机端都有等价的向量类型定义,区别就是类型名字加了cl_
前缀,如内核代码中int2
类型在主机端是cl_int2
,内核代码中float4
类型在主机端是cl_float4
,
参见下面的cl_float4
的定义:
typedef union{ cl_float CL_ALIGNED(16) s[4];#if __CL_HAS_ANON_STRUCT__ __CL_ANON_STRUCT__ struct{ cl_float x, y, z, w; }; __CL_ANON_STRUCT__ struct{ cl_float s0, s1, s2, s3; }; __CL_ANON_STRUCT__ struct{ cl_float2 lo, hi; };#endif#if defined( __CL_FLOAT2__) __cl_float2 v2[2];#endif#if defined( __CL_FLOAT4__) __cl_float4 v4;#endif}cl_float4;// 摘自cl_platform.h
从上面cl_float4
的定义可以看出主机端的cl_float4
是个联合体,默认是以数字下标访问向量元素的(s[0],s1,s[2],s[3])。同时它也支持以别名(x,y,z,w,s0~s3)访问元素。
编译器差异
不过你也看到了这些别名都定义在匿名结构体(anonymous struct)中,而匿名结构体并不是C语言标准的一部分,是编译器自行实现的,所以__CL_HAS_ANON_STRUCT__
宏开关决定编译器是否支持匿名结构体(anonymous struct),控制着是否允许使用别名访问元素。
于是我顺藤摸瓜找到__CL_HAS_ANON_STRUCT__
定义的位置,就是下面这段代码(中文部分是作者加的注释)
/* Define capabilities for anonymous struct members. */#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ )// gcc下如果没定义__STRICT_ANSI__,则__CL_HAS_ANON_STRUCT__为1#define __CL_HAS_ANON_STRUCT__ 1#define __CL_ANON_STRUCT__ __extension__#elif defined( _WIN32) && (_MSC_VER >= 1500)// VS2008以后支持匿名结构体,但会有警告,所以这里会有关闭C4201警告 /* Microsoft Developer Studio 2008 supports anonymous structs, but * complains by default. */#define __CL_HAS_ANON_STRUCT__ 1#define __CL_ANON_STRUCT__ /* Disable warning C4201: nonstandard extension used : nameless * struct/union */#pragma warning( push )#pragma warning( disable : 4201 )#else// gcc下如果定义了__STRICT_ANSI__,则__CL_HAS_ANON_STRUCT__为0#define __CL_HAS_ANON_STRUCT__ 0#define __CL_ANON_STRUCT__#endif// 摘自cl_platform.h
上面这段代码控制了__CL_HAS_ANON_STRUCT__
的定义,可以看出,在使用gcc编译时,__CL_HAS_ANON_STRUCT__
是否为1,取决于是否定义了__STRICT_ANSI__
。
如果定义了__STRICT_ANSI__
,__CL_HAS_ANON_STRUCT__
为0,否则为1。
也就是说,在gcc下编译,如果定义__STRICT_ANSI__
就没办法使用别名访问向量元素。
下图就是我在Eclipse+MinGW(5.2.0)环境下打开cl_platform.h
看到的__CL_HAS_ANON_STRUCT__
的定义,说明__STRICT_ANSI__
被定义了,
根本原因
那么接下来的问题就是:__STRICT_ANSI__
是个什么鬼?
关于__STRICT_ANSI__
来历,请参见我的上一篇博客《C++11:MinGW当指定-std=c++11选项时 默认定义了__STRICT_ANSI__
》(其实本文的答案也隐藏在这篇博客里)
从这篇博客的标题就可以得知,如果编译代码时使用了-ansi
选项,编译器就会定义__STRICT_ANSI__
,我找遍了整个项目代码,确信没有使用过-ansi
(太高端我从来不知道这个选项),所以并不是因为我使用了-ansi
才造成这个问题,而是因为我使用了-std=c++11选
项导致编译器自动定义了__STRICT_ANSI__
。
解决方案
知道了问题的根本原因,解决问题的办法也就有了。
方案1:
第一个办法就是前述博客中最后提到的办法:在使用-std=c++11选项的同时,加上-U__STRICT_ANSI__选项, 用于去掉__STRICT_ANSI__
定义
如果你是用cmake来编译项目代码,可以在CMakeList.txt中加入这样的代码
#判断编译器类型,如果是gcc编译器,则在编译选项中加入c++11支持,并去掉__STRICT_ANSI__定义if(CMAKE_COMPILER_IS_GNUCXX) add_compile_options(-std=c++11) message(STATUS "optional:-std=c++11") add_compile_options(-U__STRICT_ANSI__) message(STATUS "optional:-U__STRICT_ANSI__") endif(CMAKE_COMPILER_IS_GNUCXX)
方案二
修改你的源代码,在#include <CL/cl.hpp>
或#include <CL/opencl.h>
语句之前使用#undef __STRICT_ANSI__
删除__STRICT_ANSI__
定义
#if defined( __GNUC__) && defined( __STRICT_ANSI__ )#define __STRICT_ANSI__DEFINED__//删除__STRICT_ANSI__定义#undef __STRICT_ANSI__ #endif#include <CL/cl.hpp>#ifdef __STRICT_ANSI__DEFINED__#undef __STRICT_ANSI__DEFINED__//恢复__STRICT_ANSI__定义#define __STRICT_ANSI__#endif
代码做上述修改后,重新rebuild index
,
再打开cl_platform.h
看到的__CL_HAS_ANON_STRUCT__
的定义,说明__STRICT_ANSI__
没有被定义,
这时再看cl_int的定义,也正常了
这两种解决方案,你可以根据自己的需要来选择,但第二种方案的没有副作用,不会影响项目中其他部分代码的编译。第一种方案会有潜在的副作用,就是可能会影响项目中与opencl无关的代码的编译。
- opencl:C++11下使用别名(x,y,z,hi,lo...)访问vector类型(cl_int2,cl_long16...)的元素
- OPENCL ROTATION x y z axis
- 计算函数F(x,y,z)=(x+y)/(x-y)+(z+y)/(z-y)的值
- x > y ? y : x > z ? z : x;
- C++:使用vector的元素
- hdu4282 x^z+y^z+x*y*z=k 解的个数
- CATransform3DMakeRotation的x,y,z参数
- (X * Y) % Z
- x/y/z轴
- 10.x.y.z和100.x.y.z的那点故事和事故
- 用高斯消去法解方程组2x-y-z=4,3x+4y-2z=11,3x-2y+4z=11的解
- translate3d(x,y,z)在页面布局中的使用
- X/Y/Z Modem区别
- z = 16*x + y
- DUMP(w[,x[,y[,z]]])
- 求(x-y+z)*2
- 获取Dom元素的X/Y坐标
- C经典 使用递归求x的y次方
- 二叉树
- Linux基础知识
- 这些小工具让你的Android 开发更高效
- 动态分配内存的函数在两个库函数中
- plsql问题备忘
- opencl:C++11下使用别名(x,y,z,hi,lo...)访问vector类型(cl_int2,cl_long16...)的元素
- lanoj--1606--Funny Sheep(规律水题)
- S5PV210中断处理的编程实践1~2
- 滑动条
- C语言字符串转换为oc
- 【剑指offer系列】 复杂链表的复制___26
- jdk1.6容器-LinkedList源码
- Mybatis分页
- 线程饥饿死锁