写入 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
pTable
是 uint16_t
指针,val 是 void
指针;所以我想把它改成
pTable[i] = ((uint16_t *)val)[i]; // case 2
并发现输出中的一些差异。所以我开始首次亮相,发现记忆的排列方式有所不同。假设 void 指针中的数据类似于 val[0] = 0x1234
和 val[1] = 0x5678
addr 56781234
在第二个(案例 2)中,内存转储显示 addr 00001234 00005678
代码很大,不是我的,我不能放在这里,但它是一个解析器(它从文件中读取值)。到达该 void 指针的可能是 int
或 float
值(在我的例子中,它们是 int
)。
我想这是关于解释指针数据的事情,但我自己无法解释,有人可以向我解释吗?谢谢
【问题讨论】:
如果val
指向int
数组中的第一个元素,那么您的更改违反了严格的别名规则。
它不是分配指针,而是复制它们指向的值指针。而uint16_t*
演员表是val
打破严格别名规则的错误类型。正如你所说的pTable
是一个指针,所以pTable[i]
是指向的值,即uint16_t
这些都没有任何意义。 pTable
是 uint16_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 [重复]