首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用金属着色语言将浮点指针转换为uint8_t指针?

如何用金属着色语言将浮点指针转换为uint8_t指针?
EN

Stack Overflow用户
提问于 2021-06-15 16:58:49
回答 3查看 536关注 0票数 1

我试图在kernel void函数中用金属阴影语言编写以下C代码:

代码语言:javascript
复制
float f = 2.1;
uint8_t byteArray[sizeof(f)];
for (int a = 0; a < sizeof(f); a++) {
    byteArray[a] = ((uint8_t*)&f)[a];
}

代码应该得到浮点值的字节数组。当我试图用Metal语言编写相同的代码时,我会得到以下构建时错误:

指针类型必须具有显式地址空间限定符。

我理解金属限制了指针的使用,并要求内核函数的参数具有显式的地址空间属性,如deviceconstant等。我将如何用金属阴影语言执行类型转换?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-06-15 20:21:14

这不是C++,所以你必须用另一种方式去做。

在MSL中不能正确使用unions或reinterpret_cast

相反,有一个向量的类型为4 uint8_ts,它是uchar4

要做你想做的事,你可以写成这样。

代码语言:javascript
复制
float f = 2.1;
uchar4 ff = as_type<uchar4>(f);

请参阅MSL 等级库,第2.19节类型转换和重新解释数据.

至于地址空间限定符:

金属阴影语言中的每个指针都有一个地址限定符。它可以是deviceconstantthreadthreadgroup等。请参阅规范的第4章。

这些地址限定符来自于内存空间不同的事实。您可以在上面的文档中读到更多关于它们的信息。

因为f是局部变量,所以它位于thread空间中,所以uint8_t指针将有一种thread uint8_t*类型,而不仅仅是uint8_t

所以你可以这样做:

代码语言:javascript
复制
float f = 2.1;
thread uint8_t* ff = (thread uint8_t*)&f;

但我认为as_type的方法要清楚得多。

票数 2
EN

Stack Overflow用户

发布于 2021-06-15 17:23:59

不知道metal的具体情况,但在普通C中,您可能希望将fbyteArray放在union

下面是一些示例代码:

代码语言:javascript
复制
#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;
}

这是程序输出:

代码语言:javascript
复制
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只获得一个字节指针,就没有问题了。它甚至不是“实现定义的”行为。

就像:

代码语言:javascript
复制
float my_f = f;
uint8_t *byteArray = (uint8_t *) &my_f;

而且,它起作用了,因为它必须起作用。

此外,这里使用的union是一个常见的成语,可以追溯到1970年代,因此必须支持它。

而且,它之所以有效,是因为它必须经过设计。

如果我们有:

代码语言:javascript
复制
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");
}

为了好玩,假设funcAfuncB位于单独的.c文件中。当funcA被调用时,它以一种可预测的方式改变u的内存。

之间没有任何更改u布局的内容。

然后,我们称之为funcBbyteArray中字节的布局将是相同的/可预测的数据。

这类似于并以二进制数据的形式将float写入文件:

代码语言:javascript
复制
#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。

代码语言:javascript
复制
#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;
}
票数 1
EN

Stack Overflow用户

发布于 2021-06-15 19:11:59

在c++ (20)中有bit_cast。在“备注”一节中,您将看到它只是作为对memcpy的调用实现的。

因此,为了避免“未定义的行为”和安全(除了以前的行为外,它也是最快的),只需:

代码语言:javascript
复制
memcpy(byteArray, &f, sizeof f); //size of byteArray must be at least: sizeof f
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67990565

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档