【问题标题】:What does *(int*)(buffer) mean?*(int*)(buffer) 是什么意思?
【发布时间】:2016-09-06 09:06:57
【问题描述】:

在我正在阅读的 c++ 代码中,发现以下内容。 谁能帮我理解以下语句的作用?

char buffer[4096];
// some code
int size = *(int*)(buffer);

【问题讨论】:

  • 你知道(int*)buffer是什么意思吗?如果没有阅读关于 casting 的内容。你知道一元解引用运算符* 做了什么(例如,如果你有*some_pointer 会发生什么)?如果没有读过。然后将每个主题的知识组合起来,就像它们组合成你想知道的表达方式一样。
  • 此语句也可能导致某些架构的对齐异常。
  • 这个语句也会导致未定义的行为。
  • 它获取buffer 的地址,将其转换为int *,然后解除对结果指针的引用,这是未定义的行为。特别是,不能保证buffer 在接受int 边界上对齐。行为未定义。您不应尝试运行此代码。

标签: c++ c pointers


【解决方案1】:

它获取buffer[0] 的地址,将其转换为int*,取消引用,并使用取消引用的值初始化size。换句话说,它获取buffer 的第一个sizeof(int) 字节,假装这些字节是int,并将该int 的值存储在size 中。

【讨论】:

  • 它不直接buffer[0]的地址。相反,数组 衰减 为指向其第一个元素的指针。
  • 我不能放弃投票,直到回答回答也解释了为什么这个代码被破坏并且不应该被使用。
【解决方案2】:
char buffer[4096];//this is an array of 4096 characters
// some code

int size = *(int*)(buffer);

会将(衰减的)字符指针buffer 转换为整数指针。然后它取消引用它以获得一个整数值。您从中获得的整数值将由 buffer 数组的前 4 个字符值组成,假设您的机器中 int 的大小为 4 个字节,或者通常由 sizeof(int) 字符组成。

换句话说,buffer 数组的第一个 sizeof(int) 字符的内存表示将被视为代表单个整数值,因为现在它由整数指针指向,这将是当该整数指针被取消引用时,存储在size 整数变量中。

话虽如此,正如 cmets 部分中反复声明的那样,此代码是不安全的。想到的一件事是,一些 CPU 有严格的对齐要求(参见 this answer),在这种情况下,不能保证 buffer 数组的第一个元素的地址符合整数导致这些 CPU 中的未定义操作。

请参阅@Lundin 回答,了解有关此代码不安全且可能无法为您提供所需结果的更多原因。

【讨论】:

  • @user694733,是的,由于指向 int 的指针的内存对齐错误,它可能会在某些架构上崩溃
  • @user694733 感谢您的反馈,我试图提及一个原因,我知道这会导致某些 CPU 上的操作未定义。 Lundin 的回答更详细地说明了这段代码的问题,我觉得我会回应已经说过的话。
【解决方案3】:

谁能帮我理解以下语句的作用?

第一句话:

char buffer[4096];

声明一个大小为4096chars数组。

第二条语句:

int size = *(int*)(buffer);

1. 首先将衰减的字符指针指向数组buffer(也称为buffer),这是一个指向其第一个元素的指针,在其声明时设置

2. 然后将其转换为指向intint* 的指针

3.最后,将此指针的内容(类型为int)分配给变量size

【讨论】:

  • "先获取数组buffer的地址"是错误的,获取buffer的地址会是&buffer。取而代之的是buffer衰减为指向其第一个元素的指针
  • 我不能放弃投票,直到回答回答也解释了为什么这个代码被破坏并且不应该被使用。
  • @user694733 确实,如果只有一个答案清楚地解释了为什么这是 ub。
【解决方案4】:

TL;DR:这段代码很糟糕,忘记它并继续吧。


(buffer) 这个括号意味着程序员对自己的编程能力不安全。

由于buffer 是一个字符数组,因此单独使用标识符buffer 会为您提供指向第一个元素的指针:char 指针。

(int*) 这是一个转换,将char 指针转换为int 指针。

* 获取该整数指针的内容,并将结果存储在整数 size 中。

请注意,此代码完全不安全。许多指针转换调用定义不明确的行为。可能存在对齐问题。可能存在指针别名问题(谷歌“严格别名规则”)。这个特定的代码也是字节序相关的,这意味着它要求字符数组的内容具有给定的字节顺序。

总体而言,在执行此类操作时使用 intchar(可能已签名)之类的签名类型没有任何意义。特别是,char 类型非常有问题,因为它具有实现定义的签名,应该避免。请改用unsigned charuint8_t

稍微不那么糟糕的代码看起来像这样:

#include <stdint.h>

uint8_t buffer[4096];
// some code
uint32_t size = *(uint32_t*)buffer;

【讨论】:

  • 我认为您的示例代码根本不应该使用指针取消引用技巧。使用memcpy 仍然可能存在字节顺序问题,但至少不会出现UB。
  • 仍然具有相同未定义行为的代码如何不那么糟糕?
  • @2501 因为它没有提到的类型问题。演示如何解决这个问题是代码 sn-p 的目的。要修复未定义的行为,您需要做一些更激进的事情。
  • 建议的替代方案存在一个问题:它施加了原始代码中不存在的约束,即目标硬件必须提供 8 位原生类型和 32 位原生类型.这可能是一个有效的更改,但是与原始代码强加不同要求的代码示例应该指出这些差异。 unsigned char 将永远存在; uint8_t 可能不会。
猜你喜欢
  • 1970-01-01
  • 2015-08-28
  • 2011-06-05
  • 2021-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多