1
void *vp = (void *)5;
uint8_t i = (uint8_t)vp;

i == 5 在所有 8 位和更高的 CPU 上都可以吗?这样做有什么风险?有没有更好的方法让变量在 C99 中存储 8 位整数文字或指针?

我有一个函数指针数组,指向带有 void * 的函数。某些函数需要将 void * 解释为 uint8_t。

4

2 回答 2

3

void *vp = 5;不应该编译;C 标准至少要求编译器发出诊断消息。您可以使用 请求转换void *vp = (void *) 5;,也可以使用 请求反向转换(uint8_t) vp。C 标准不保证这将再现原始值。(涉及指针的转换在 C 2018 6.3.2.3 中指定。)它可能适用于大多数 C 实现。

C 标准定义的替代方法是使用偏移量到您已经拥有的一些足够大的对象中。例如,如果你有一些 array A,并且你想n在 a中存储一些小数字void *,那么你可以这样做:

void *vp = (char *) A + n; // Point n bytes into the object A.

您可以通过以下方式恢复号码:

(char *) vp - (char *) A // Subtract base address to recover offset.
于 2021-06-30T23:04:17.850 回答
2

C 标准确实允许整数和指针之间的转换,但是它并没有准确解释它应该如何发生。这取决于每个特定的实现。

C 标准的第 6.3.2.3 节 p5-6描述了这些转换:

5整数可以转换为任何指针类型。除非前面指定,结果是实现定义的,可能没有正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。

6任何指针类型都可以转换为整数类型。除非前面指定,结果是实现定义的。如果结果不能以整数类型表示,则行为未定义。结果不必在任何整数类型的值范围内。

特别是在 gcc 下,您正在做的事情会起作用,但是不能保证在所有编译器或架构上都可以使用。

然而,保证工作的是采用复合文字的地址

void *vp = &(uint8_t){5};
uint8_t i = *(uint8_t *)vp;

这将创建一个临时类型的对象uint8_t并获取其地址。然后可以void *根据 6.3.2.3 的第 1 段将该地址转换为完全符合标准的 a 并返回:

指向的指针void可以转换为指向任何对象类型的指针或从指向任何对象类型的指针转​​换。 指向任何对象类型的指针都可以转换为指向void和返回的指针;结果应与原始指针比较。

复合文字的生命周期是定义它的块的生命周期。因此,只要在该块结束后不使用指针,它就会起作用。

但是,如果您打算将其传递给启动线程的函数,则最好为该值动态分配内存并传递该值。否则,您将面临定义复合文字的函数在线程函数运行时返回的风险,这可能会尝试使用该指针。

于 2021-07-01T00:34:41.087 回答