Metal Shading Language中获取数组长度异常问题求助
解决Metal Shading Language中数组传递后长度获取异常的问题
问题根源
当你把数组作为参数传递给函数时,MSL会和C/C++一样,将数组隐式转换为指向第一个元素的指针。这时候在函数内部,arr不再是数组类型,而是指针类型,所有依赖数组类型的长度计算都会失效。
为什么你的两种方法都不对
sizeof(arr)/sizeof(arr[0]):在64位Metal平台上,指针大小是8字节,uint类型是4字节,8/4=2——你计算的是指针大小和单个元素大小的比值,而非数组实际长度,这就是结果为2的原因。*(&arr +1)-arr:这里的arr是指针,&arr是指向指针的指针,&arr+1跳过的是一个指针的内存空间,解引用后和原指针相减结果必然是0,完全和数组长度无关。
可行解决方案
方案1:显式传递数组长度
在调用函数时,直接把数组长度作为参数传入——因为在数组定义的函数(testFrag)里,sizeof能正确获取数组的总大小,计算出长度后传递给目标函数:
float4 testSize(uint arr[], size_t length, float2 uv) { // 直接使用传入的length return float4(fract(uv.x * length), 0, 0, 1); } fragment float4 testFrag(VertexOut input[[stage_in]]) { float2 uv = input.textureCoordinate; uint text[] = {4, 3, 8, 5, 3, 32, 5, 7, 8}; size_t textLength = sizeof(text)/sizeof(text[0]); float4 col = testSize(text, textLength, uv); return col; }
方案2:使用模板函数自动推导数组长度
利用MSL对模板的支持,让编译器在编译期自动推导数组的大小,避免手动传递长度:
template <size_t N> float4 testSize(uint (&arr)[N], float2 uv) { // N就是编译期推导的数组长度 return float4(fract(uv.x * N), 0, 0, 1); } fragment float4 testFrag(VertexOut input[[stage_in]]) { float2 uv = input.textureCoordinate; uint text[] = {4, 3, 8, 5, 3, 32, 5, 7, 8}; // 直接传数组,编译器自动推导N=9 float4 col = testSize(text, uv); return col; }
方案3:使用固定大小数组(适合长度固定的场景)
如果你的数组长度是固定不变的,可以直接定义固定大小的数组,函数参数也指定相同的大小,这样sizeof就能正确计算数组长度:
// 参数指定固定大小的数组 float4 testSize(uint arr[9], float2 uv) { size_t size = sizeof(arr)/sizeof(arr[0]); // 此时sizeof(arr)是9*4=36,计算结果为9 return float4(fract(uv.x * size), 0, 0, 1); } fragment float4 testFrag(VertexOut input[[stage_in]]) { float2 uv = input.textureCoordinate; uint text[9] = {4, 3, 8, 5, 3, 32, 5, 7, 8}; // 定义固定大小数组 float4 col = testSize(text, uv); return col; }
内容的提问来源于stack exchange,提问作者Nimrod7
相关产品推荐
相关产品推荐

