将字节存储在 void 指针跨平台安全吗?
Is storing a byte in a void pointer cross-platform safe?
void *vp = (void *)5;
uint8_t i = (uint8_t)vp;
我会在所有 8 位和更高的 CPU 上 == 5 吗?这样做有什么风险?在 C99 中,有没有更好的方法让变量存储 8 位整数文字或指针?
我有一个函数指针数组,指向采用 void * 的函数。某些函数需要将 void * 解释为 uint8_t.
void *vp = 5;
不应该编译; C 标准至少要求编译器发出诊断消息。您可以使用 void *vp = (void *) 5;
请求转换,也可以使用 (uint8_t) vp
请求反向转换。 C 标准不保证这将重现原始值。 (涉及指针的转换在C 2018 6.3.2.3中指定。)它可能适用于大多数C实现。
C 标准定义的替代方法是对您已有的足够大的对象使用偏移量。例如,如果你有一些数组 A
,你想在 void *
中存储一些小数字 n
,那么你可以这样做:
void *vp = (char *) A + n; // Point n bytes into the object A.
您可以通过以下方式恢复号码:
(char *) vp - (char *) A // Subtract base address to recover offset.
C 标准确实允许在整数和指针之间进行转换,但是它并没有准确解释它应该如何发生。这留给每个特定的实现。
C standard 的第 6.3.2.3 p5-6 节描述了这些转换:
5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined,
might not be correctly aligned, might not point to an entity
of the referenced type, and might be a trap representation.
6 Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the
result cannot be represented in the integer type,the behavior
is undefined. The result need not be in the range of values
of any integer type.
特别是在 gcc 下,您正在做的事情会起作用,但是不能保证它在所有编译器或体系结构上都起作用。
是保证工作的是获取复合文字的地址:
void *vp = &(uint8_t){5};
uint8_t i = *(uint8_t *)vp;
这将创建一个 uint8_t
类型的临时对象并获取其地址。然后可以根据 6.3.2.3 的第 1 段将该地址转换为完全符合标准的 void *
和返回:
A pointer to void
may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void
and back again; the result shall compare equal to the original pointer.
复合文字的生命周期是它在其中定义的块的生命周期。因此,只要在该块结束后不使用指针,它就会起作用。
但是,如果您打算将它传递给启动线程的函数,最好为该值动态分配内存并传递它。否则,您 运行 在线程函数 运行ning 可能尝试使用该指针时返回定义复合文字的函数的风险。
void *vp = (void *)5;
uint8_t i = (uint8_t)vp;
我会在所有 8 位和更高的 CPU 上 == 5 吗?这样做有什么风险?在 C99 中,有没有更好的方法让变量存储 8 位整数文字或指针?
我有一个函数指针数组,指向采用 void * 的函数。某些函数需要将 void * 解释为 uint8_t.
void *vp = 5;
不应该编译; C 标准至少要求编译器发出诊断消息。您可以使用 void *vp = (void *) 5;
请求转换,也可以使用 (uint8_t) vp
请求反向转换。 C 标准不保证这将重现原始值。 (涉及指针的转换在C 2018 6.3.2.3中指定。)它可能适用于大多数C实现。
C 标准定义的替代方法是对您已有的足够大的对象使用偏移量。例如,如果你有一些数组 A
,你想在 void *
中存储一些小数字 n
,那么你可以这样做:
void *vp = (char *) A + n; // Point n bytes into the object A.
您可以通过以下方式恢复号码:
(char *) vp - (char *) A // Subtract base address to recover offset.
C 标准确实允许在整数和指针之间进行转换,但是它并没有准确解释它应该如何发生。这留给每个特定的实现。
C standard 的第 6.3.2.3 p5-6 节描述了这些转换:
5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.
6 Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type,the behavior is undefined. The result need not be in the range of values of any integer type.
特别是在 gcc 下,您正在做的事情会起作用,但是不能保证它在所有编译器或体系结构上都起作用。
是保证工作的是获取复合文字的地址:
void *vp = &(uint8_t){5};
uint8_t i = *(uint8_t *)vp;
这将创建一个 uint8_t
类型的临时对象并获取其地址。然后可以根据 6.3.2.3 的第 1 段将该地址转换为完全符合标准的 void *
和返回:
A pointer to
void
may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer tovoid
and back again; the result shall compare equal to the original pointer.
复合文字的生命周期是它在其中定义的块的生命周期。因此,只要在该块结束后不使用指针,它就会起作用。
但是,如果您打算将它传递给启动线程的函数,最好为该值动态分配内存并传递它。否则,您 运行 在线程函数 运行ning 可能尝试使用该指针时返回定义复合文字的函数的风险。