我试图在kernel void函数中用金属阴影语言编写以下C代码:
float f = 2.1;
uint8_t byteArray[sizeof(f)];
for (int a = 0; a < sizeof(f); a++) {
byteArray[a] = ((uint8_t*)&f)[a];
}代码应该得到浮点值的字节数组。当我试图用Metal语言编写相同的代码时,我会得到以下构建时错误:
指针类型必须具有显式地址空间限定符。
我理解金属限制了指针的使用,并要求内核函数的参数具有显式的地址空间属性,如device、constant等。我将如何用金属阴影语言执行类型转换?
发布于 2021-06-15 20:21:14
这不是C++,所以你必须用另一种方式去做。
在MSL中不能正确使用unions或reinterpret_cast。
相反,有一个向量的类型为4 uint8_ts,它是uchar4。
要做你想做的事,你可以写成这样。
float f = 2.1;
uchar4 ff = as_type<uchar4>(f);请参阅MSL 等级库,第2.19节类型转换和重新解释数据.
至于地址空间限定符:
金属阴影语言中的每个指针都有一个地址限定符。它可以是device,constant,thread,threadgroup等。请参阅规范的第4章。
这些地址限定符来自于内存空间不同的事实。您可以在上面的文档中读到更多关于它们的信息。
因为f是局部变量,所以它位于thread空间中,所以uint8_t指针将有一种thread uint8_t*类型,而不仅仅是uint8_t。
所以你可以这样做:
float f = 2.1;
thread uint8_t* ff = (thread uint8_t*)&f;但我认为as_type的方法要清楚得多。
发布于 2021-06-15 17:23:59
不知道metal的具体情况,但在普通C中,您可能希望将f和byteArray放在union中
下面是一些示例代码:
#include <stdio.h>
#include <stdint.h>
union float_byte {
float f;
uint8_t byteArray[sizeof(float)];
};
union float_byte u;
void
dotest(float f)
{
u.f = f;
printf("%.6f",u.f);
for (int idx = 0; idx < sizeof(u.byteArray); ++idx)
printf(" %2.2X",u.byteArray[idx]);
printf("\n");
}
int
main(void)
{
dotest(2.1);
dotest(7.6328);
return 0;
}这是程序输出:
2.100000 66 66 06 40
7.632800 E6 3F F4 40更新:
即使到了今天,从技术上讲,读一位工会会员,这不是最后一封信吗?虽然,这听起来像现在广泛支持的实现定义的行为。许多相关问题之一:stackoverflow.com.…/问询/2310483/…-雅诺
不,这不是UB有很多原因。
它可能是“实现定义的”行为,但仅仅是因为CPU/处理器的endianness。内存中32位float的格式,如果我们希望解释byteArray中的字节
但是,AFAICT,这并不影响OP的问题,因为问题的关键是为数据的二进制/序列化获取一个字节缓冲区?
如果要解释数据(例如设计DIYF.P.S/W实现),则必须知道float的格式和功能。这可能是IEEE 784格式和处理器的功能。
但是,使用union只获得一个字节指针,就没有问题了。它甚至不是“实现定义的”行为。
就像:
float my_f = f;
uint8_t *byteArray = (uint8_t *) &my_f;而且,它起作用了,因为它必须起作用。
此外,这里使用的union是一个常见的成语,可以追溯到1970年代,因此必须支持它。
而且,它之所以有效,是因为它必须经过设计。
如果我们有:
void
funcA(float f)
{
u.f = f;
}
void
funcB(void)
{
for (int idx = 0; idx < sizeof(u.byteArray); ++idx)
printf(" %2.2X",u.byteArray[idx]);
printf("\n");
}为了好玩,假设funcA和funcB位于单独的.c文件中。当funcA被调用时,它以一种可预测的方式改变u的内存。
之间没有任何更改u布局的内容。
然后,我们称之为funcB。byteArray中字节的布局将是相同的/可预测的数据。
这类似于并以二进制数据的形式将float写入文件:
#include <unistd.h>
int fd;
void
writefloat(float f)
{
float my_f = f;
write(fd,&my_f,sizeof(float));
}
void
writefloat2(float f)
{
write(fd,&f,sizeof(float));
}
void
writefloat3(float f)
{
write(fd,&f,sizeof(f));
}如果我们使用的是uint32_t而不是float,这可能会更容易一些。我们可以做个endian测试。注:这是粗糙的,不考虑像pdp11 11/vax那样的奇怪的endianness。
#include <stdio.h>
#include <stdint.h>
union uint_byte {
uint32_t i;
uint8_t b[sizeof(uint32_t)];
};
union uint_byte u;
int
main(void)
{
u.i = 0x01020304;
if (u.b[0] == 0x04)
printf("cpu is little-endian\n");
else
printf("cpu is big-endian\n");
return 0;
}发布于 2021-06-15 19:11:59
在c++ (20)中有bit_cast。在“备注”一节中,您将看到它只是作为对memcpy的调用实现的。
因此,为了避免“未定义的行为”和安全(除了以前的行为外,它也是最快的),只需:
memcpy(byteArray, &f, sizeof f); //size of byteArray must be at least: sizeof fhttps://stackoverflow.com/questions/67990565
复制相似问题