写入 int vs uint16_t 时的内存填充

Posted

技术标签:

【中文标题】写入 int vs uint16_t 时的内存填充【英文标题】:Memory filling when writing int vs uint16_t 【发布时间】:2018-01-25 12:47:10 【问题描述】:

我一直在看一些代码,我看到了一个有趣的事情:在某些时候有一行

pTable[i] = ((int *)val)[i]; // case 1

pTableuint16_t 指针,val 是 void 指针;所以我想把它改成

pTable[i] = ((uint16_t *)val)[i]; // case 2

并发现输出中的一些差异。所以我开始首次亮相,发现记忆的排列方式有所不同。假设 void 指针中的数据类似于 val[0] = 0x1234val[1] = 0x5678

在第一种情况下(情况 1),内存转储显示addr 56781234 在第二个(案例 2)中,内存转储显示 addr 00001234 00005678

代码很大,不是我的,我不能放在这里,但它是一个解析器(它从文件中读取值)。到达该 void 指针的可能是 intfloat 值(在我的例子中,它们是 int)。

我想这是关于解释指针数据的事情,但我自己无法解释,有人可以向我解释吗?谢谢

【问题讨论】:

如果val 指向int 数组中的第一个元素,那么您的更改违反了严格的别名规则。 它不是分配指针,而是复制它们指向的值指针。而uint16_t* 演员表是val 打破严格别名规则的错误类型。正如你所说的pTable 是一个指针,所以pTable[i] 是指向的值,即uint16_t 这些都没有任何意义。 pTableuint16_t 指针... 是的,这是一个很好的问题:为什么使用 uint16_t 表示 int 或 float 值?! 【参考方案1】:

int 在您的系统上可能是 32 位,而 uint16_t 是 16 位。

这意味着您将在第一种情况下访问地址为val[i] 的 32 位信息,而在第二种情况下仅访问 16 位信息。

由于[] 运算符根据val 的类型转换为此*(val + i),因此内存中的位置也会发生变化。 也就是说((int *)val)[i];((uint16_t *)val)[i];不在同一个地址,除非i为0;

'i' 乘以sizeof(val[0]) 将确定val 地址的偏移量。

【讨论】:

doh... 我明白了,如果我将 void 转换为 uint16 并将 void 点转换为 int,我将得到 00001234,因为有 2 个 uint16 值代表 32 bts int...我怎么没看到?!谢谢大家【参考方案2】:

让我们将pTable[i] = ((int *)val)[i]; 分割成几段,以便于理解:

void* val = something;             // val points to an object of some type.
uint16_t* pTable = something_else; // ptable points to a uint16_t object

int* intPtr = (int *)val; // We assume that val points to an int object.

int value = intPtr[i];    // Furthermore, we assume that the pointed int
                          // object is within an array of int objects.
                          // This expression gets the value of an int
                          // object that is i'th sibling element after
                          // the one pointed by val.

uint16_t converted = value; // This step is an implicit conversion
                            // in the original line.

pTable[i] = converted; // we assume that pTable also points to an
                       // element of an array and assign the i'th 
                       // successor of element pointed by pTable

因此,如果您将演员表从(int*) 更改为(uint16_t*),那么您将假设val 指向uint16_t 的数组。显然这与val 指向int 数组的假设相矛盾。

因此,如果我们假设原始程序是正确的,那么val 确实指向int 的数组。因此,使用指向 uint16_t 的指针读取此类值将具有未定义的行为,因为这违反了指针别名规则。

【讨论】:

以上是关于写入 int vs uint16_t 时的内存填充的主要内容,如果未能解决你的问题,请参考以下文章

处理代码重新定义 int 类型(uint16_t、int16_t 等)和 Boost 不喜欢它

使用指针写入内存[关闭]

将 int16_t 变量转换为 uint8_t 以传递给函数

将两个 uint16_t 数字相乘得到一个 int [重复]

动态整数大小:int64_t、int32_t、uint32_t 等

uint8_t / uint16_t / uint32_t /uint64_t 这些数据类型是什么?