clCreateProgramWithSource传入#include字符数组地址出现段错误问题
问题根因
clCreateProgramWithSource的第三个参数strings类型为const char **,要求传入字符串指针数组的首地址。函数内部会先对该二级指针解引用,拿到存储的字符串指针,再访问该指针指向的内存读取源码内容。
正常写法逻辑
const char *cl_srcs[1]; cl_srcs[0] = prog_src_cl; cl.prog = clCreateProgramWithSource(cl.context, 1, cl_srcs, NULL, &err);
cl_srcs是长度为1的const char*数组,首元素存储的是prog_src_cl对应的源码字符串首地址- 数组传参时自动退化为指向首元素的指针,类型与函数要求的
const char **完全匹配 - 函数解引用后拿到合法的源码地址,可正常读取内容
段错误写法的问题
cl.prog = clCreateProgramWithSource(cl.context, 1, &prog_src_cl, NULL, &err);
核心原因是对prog_src_cl的类型判断存在误差:绝大多数OpenCL源码头文件中,嵌入的源码会被定义为字符数组unsigned char prog_src_cl[],而非你以为的unsigned char *指针类型,两种类型的取地址逻辑完全不同:
- 若
prog_src_cl是数组类型,&prog_src_cl是数组指针,类型为unsigned char (*)[N](N为数组长度),它的数值和数组首地址相同,但类型完全不匹配const char **的要求 - 函数将传入的数组指针当做二级指针解引用时,会从数组首地址开始读取4/8个字节(与系统指针长度一致),这部分内容是源码的前几个字符,会被误当做内存指针访问,直接触发非法内存访问的段错误。
类型验证方法
直接打印sizeof(prog_src_cl)即可判断真实类型:
- 若为指针类型:32位系统输出4,64位系统输出8
- 若为数组类型:输出值等于源码字符串总长度+1(包含末尾的
\0结束符)
替代修复方案
如果不想额外定义指针数组,也可以用复合字面量实现参数类型匹配:
cl.prog = clCreateProgramWithSource(cl.context, 1, (const char **)&(const char*){prog_src_cl}, NULL, &err);
内容的提问来源于stack exchange,提问作者Sam P
相关产品推荐
相关产品推荐

