读取空白*指向字符作为整数的安全性

How safe is reading a void * pointing to a char as an int?

本文关键字:整数 安全性 字符 空白 读取      更新时间:2023-10-16

读取一个空白*指向一个字符作为整数有多安全?

示例:在 8 位字符访问比 32 位整数慢得多的系统中测试 char 的第一个位。

char c = 'B'; // a char here to illustrate the potentially dangerous case, but the
              // point is this could be a char, could be an int... I am just
              // interested in the first bit
void *v = &c;
int i = *(int *)v;
if (i & 0x01)
{
    printf("yep");
}

似乎有效,但是如果我的字符 (c) 正好位于分配给此进程的有效内存的边缘,它会读取无效内存吗?还是系统足够聪明,可以在前 8 位后停止复制?

谢谢

在所有情况下,它都是未定义的行为。

在大多数实际系统中,它将从c和相邻内存中正常读取,如果c接近内存页的末尾并且相邻页被标记为不可读,则失败(访问冲突又称为分段错误)。

在数量较少但仍然不平凡的系统中,您可能会遇到对齐错误和/或读取与c重叠但在开始以外的某个位置c的 32 位值。

但是,如果编译器发现您这样做,它将获得标准许可,以非常破碎的方式"优化"所有代码。


如果您害怕 8 位访问速度较慢的系统,请使用 int_fast8_t 而不是 char 。 这允许您的构建环境选择更好的变量大小。

不,这不安全。

而且您的用例完全是人为的,因为我从未听说过读取 32 位值比读取 8 位值更快的系统。如果有的话,有时是相反的。

(即使你找到了这样的系统,也要把这样的"优化"留给编译器,它会做得更好。

系统不够聪明,你的程序容易出现内存访问违规

这只是未定义的行为。

另一方面,我可以想象这将起作用的情况。请注意,在声明 c 之后,您声明v 。由于c在堆栈上,通过将其地址转换为void*然后取消引用它,您可能会得到int,它将由 c 的 1 个字节和v的 3 个字节组成。但这只是众多可能的实现之一。

int 变量将加载 3 个字节加上您要加载的字节。此外,您的 int 转换也可能导致错位。而且,这种强制转换在平台之间不可移植,根据您在 if 中屏蔽的方式,其恩迪度不同。这是一种糟糕的方法,请重新构建您的系统以避免当前情况。