在 C 语言中,如果我投射 &取消引用指针,我先执行哪一个有关系吗?

发布于 2024-10-10 20:31:54 字数 681 浏览 5 评论 0原文

在 C 中,您可以转换简单数据类型(例如 intfloat)以及指向这些数据类型的指针。

现在我假设,如果您想从一种类型的指针转​​换为另一种类型的值(例如从 *floatint),则转换的顺序取消引用并不重要。即,对于变量 float* pf,您有 (int) *pf == *((int*) pf)。有点像数学中的交换律……

但事实似乎并非如此。我编写了一个测试程序:

#include <stdio.h>
int main(int argc, char *argv[]){
  float f = 3.3;
  float* pf = &f;
  int i1 = (int) (*pf);
  int i2 = *((int*) pf);
  printf("1: %d, 2: %d\n", i1, i2);
  return 0;
}

在我的系统上,输出是

1: 3, 2: 1079194419

因此,转换指针似乎与转换值的工作方式不同。

这是为什么?为什么第二个版本没有做我认为应该做的事情?

这是依赖于平台的,还是我以某种方式调用了未定义的行为?

In C, you can cast both simple data types like int, float, and pointers to these.

Now I would have assumed that if you want to convert from a pointer to one type to the value of another type (e.g. from *float to int), the order of casting and dereferencing does not matter. I.e. that for a variable float* pf, you have (int) *pf == *((int*) pf). Sort of like commutativity in mathematics...

However this does not seem to be the case. I wrote a test program:

#include <stdio.h>
int main(int argc, char *argv[]){
  float f = 3.3;
  float* pf = &f;
  int i1 = (int) (*pf);
  int i2 = *((int*) pf);
  printf("1: %d, 2: %d\n", i1, i2);
  return 0;
}

and on my system the output is

1: 3, 2: 1079194419

So casting the pointer seems to work differently from casting the value.

Why is that? Why does the second version not do what I think it should?

And is this platform-dependent, or am I somehow invoking undefined behaviour?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

傻比既视感 2024-10-17 20:31:54

下面说的是获取 pf 处的浮点数并将其转换为整数。这里的转换是请求将浮点数转换为整数。编译器生成将浮点值转换为整数值的代码。 (将浮点值转换为整数是“正常”的事情。)

int i1 = (int) (*pf);

下面说首先强制编译器认为 pf 指向整数(并忽略 pf 是指向浮点的指针这一事实),然后获取整数值(但它不是整数值)。这是一件奇怪而危险的事情。这种情况下的转换会禁用正确的转换。编译器在内存中执行位的简单复制(产生垃圾)。 (并且也可能存在内存对齐问题!)

int i2 = *((int*) pf);

在第二个语句中,您没有“转换”指针。您正在告诉编译器内存指向什么(在本例中,这是错误)。

这两个语句正在做非常不同的事情!

请记住,c 有时使用相同的语法来描述不同的操作。

=============

请注意,double 是 C 中的默认浮点类型(数学库通常使用 double 参数)。

The following says get the float at pf and convert it to an integer. The casting here is a request to convert the float into an integer. The compiler produces code to convert the float value to an integer value. (Converting float values to integers is a "normal" thing to do.)

int i1 = (int) (*pf);

The following says first FORCE the compiler to think pf points to an integer (and ignore the fact that pf is a pointer to a float) and then get the integer value (but it isn't an integer value). This is an odd and dangerous thing to do. The casting in this case DISABLES the proper conversion. The compiler performs a simple copy of the bits at the memory (producing trash). (And there could be memory alignment issues too!)

int i2 = *((int*) pf);

In the second statement, you are not "converting" pointers. You are telling the compiler what the memory points to (which, in this example, is wrong).

These two statements are doing very different things!

Keep in mind that c some times uses the same syntax to describe different operations.

=============

Note that double is the default floating point type in C (the math library typically uses double arguments).

天涯沦落人 2024-10-17 20:31:54

如果您先取消引用,然后再转换为 int,您将获得从 float 到 int 转换的常见(截断)行为。如果您首先转换为指向 int 的指针,然后取消引用,则该行为不是由标准定义的。通常它表现为将包含 float 的内存解释为 int。请参阅 http://en.wikipedia.org/wiki/IEEE_754-2008 了解如何实现有效。

If you dereference first, cast to int later, you will get the usual (truncation) behavior of casts from float to int. If you cast to pointer to int first, then dereference, the behaviour isn't defined by the standard. Usually it manifests in interpreting the memory that contains the float as int. See http://en.wikipedia.org/wiki/IEEE_754-2008 for how that works out.

锦爱 2024-10-17 20:31:54

当然可以!强制转换告诉编译器如何查看内存的某些部分。然后,当您访问内存时,它会尝试根据您告诉它如何查看数据来解释其中的数据。使用以下示例更容易理解。

int main()
{
    char A[] = {0, 0, 0, 1 };
    int p = *((int*)A);
    int i = (int)*A;
    printf("%d %d\n", i, p);
    return 0; 
}

32 位小端机器上的输出将为 0 16777216。这是因为 (int*)A 告诉编译器将 A 视为指向整数的指针,因此当您取消引用 A 时,它会查看从 A 开始的 4 个字节(作为 sizeof(int ) == 4)。考虑字节顺序后,4 个字节的内容计算为 16777216。另一方面,*A 取消引用 A 以获得 0(int )*A 将其转换为 0。

Of course it does! Casting tells the compiler how to look at the some section of memory. When you then access the memory, it tries to interpret the data there based on how you told it look at it. It's easier to understand it using the following example.

int main()
{
    char A[] = {0, 0, 0, 1 };
    int p = *((int*)A);
    int i = (int)*A;
    printf("%d %d\n", i, p);
    return 0; 
}

The output on a 32-bit little endian machine will be 0 16777216. This is because (int*)A tells the compiler to treat A as a pointer to integer and hence when you dereference A, it looks at the 4 bytes starting from A (as sizeof(int) == 4). After accounting for the endian-ness, the content of the 4 bytes evaluated to 16777216. On the other hand, *A dereferences A to get 0 and (int)*A casts that to get 0.

北凤男飞 2024-10-17 20:31:54

强制转换,然后取消引用意味着“假装我指向另一件事,然后获取应该指向的另一件事”。

取消引用,然后强制转换意味着“获取我实际指向的东西,然后按照通常的规则将其转换为其他东西”。

“通常的规则”可以改变位,以获得逻辑上表示相同值的另一种类型的值。假装你指着某个你实际上没有指着的东西是不可能的。

Cast, then dereference means "pretend I am pointing to this other thing, and then get the other thing that is supposedly being pointed at".

Dereference, then cast means "get the thing I am actually pointing at, and then convert it to this other thing by the usual rules".

"The usual rules" can change the bits around in order to get a value of another type that logically represents the same value. Pretending you're pointing at something you're not actually pointing at cannot.

冷夜 2024-10-17 20:31:54

int 在内存中的表示方式与 float 不同。您所看到的是,编译器认为该指针指向 int,并且它查看 32 位内存,认为它将找到一个 int,而实际上它找到的是 float 的未定义部分,这会导致一些非常严重的情况。数量很大。

An int is not represented in memory the same as a float. What you are seeing is the compiler thinking the pointer is to an int and it looks at the 32 bits of memory thinking it is going to find an int when it is in fact finding an undefined portion of the float, which comes out to some very large number.

梦醒时光 2024-10-17 20:31:54

根据标准的6.5/7,粗略地说,
存储的值必须与有效类型兼容
或字符类型。
因此,我认为语句 int i2 = *((int*) pf) 定义不明确。

According to 6.5/7 of the standard, roughly speaking,
stored value has to be compatible with the effective type
or a character type.
So, I think the statement int i2 = *((int*) pf) isn't well-defined.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文