C语言 在 C 中转换指针的规则是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17260527/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What are the rules for casting pointers in C?
提问by Theo Chronic
K&R doesn't go over it, but they use it. I tried seeing how it'd work by writing an example program, but it didn't go so well:
K&R 没有仔细研究它,但他们使用它。我试着通过编写一个示例程序来看看它是如何工作的,但它并没有那么顺利:
#include <stdio.h>
int bleh (int *);
int main(){
char c = '5';
char *d = &c;
bleh((int *)d);
return 0;
}
int bleh(int *n){
printf("%d bleh\n", *n);
return *n;
}
It compiles, but my print statement spits out garbage variables (they're different every time I call the program). Any ideas?
它编译,但我的打印语句吐出垃圾变量(每次我调用程序时它们都不同)。有任何想法吗?
回答by Gilles 'SO- stop being evil'
When thinking about pointers, it helps to draw diagrams. A pointer is an arrow that points to an address in memory, with a label indicating the type of the value. The address indicates where to look and the type indicates what to take. Casting the pointer changes the label on the arrow but not where the arrow points.
在考虑指针时,绘制图表会有所帮助。指针是指向内存中地址的箭头,带有指示值类型的标签。地址表示去哪里看,类型表示要拿什么。投射指针会更改箭头上的标签,但不会更改箭头指向的位置。
din mainis a pointer to cwhich is of type char. A charis one byte of memory, so when dis dereferenced, you get the value in that one byte of memory. In the diagram below, each cell represents one byte.
dinmain是c类型为 的指针char。Achar是一个字节的内存,所以当d被取消引用时,你会得到那一字节内存中的值。在下图中,每个单元格代表一个字节。
-+----+----+----+----+----+----+-
| | c | | | | |
-+----+----+----+----+----+----+-
^~~~
| char
d
When you cast dto int*, you're saying that dreally points to an intvalue. On most systems today, an intoccupies 4 bytes.
当您转换d为 时int*,您是在说这d确实指向了一个int值。在今天的大多数系统上,aint占用 4 个字节。
-+----+----+----+----+----+----+-
| | c | ?? | ?? | ?? | |
-+----+----+----+----+----+----+-
^~~~~~~~~~~~~~~~~~~
| int
(int*)d
When you dereference (int*)d, you get a value that is determined from these four bytes of memory. The value you get depends on what is in these cells marked ?, and on how an intis represented in memory.
当您取消引用时(int*)d,您将获得一个由这四个字节的内存确定的值。您获得的值取决于这些标记为 的单元格中的内容?,以及 aint在内存中的表示方式。
A PC is little-endian, which means that the value of an intis calculated this way (assuming that it spans 4 bytes):
* ((int*)d) == c + ?? * 2? + ?? * 21? + ?? * 22?. So you'll see that while the value is garbage, if you print in in hexadecimal (printf("%x\n", *n)), the last two digits will always be 35(that's the value of the character '5').
甲PC是小端,这意味着,一个值int被计算这种方式(假设它跨越4个字节):
* ((int*)d) == c + ?? * 2? + ?? * 21? + ?? * 22?。所以你会看到,虽然值是垃圾,但如果你以十六进制 ( printf("%x\n", *n))打印,最后两位数字将始终是35(即字符的值'5')。
Some other systems are big-endian and arrange the bytes in the other direction: * ((int*)d) == c * 22? + ?? * 21? + ?? * 2? + ??. On these systems, you'd find that the value always startswith 35when printed in hexadecimal. Some systems have a size of intthat's different from 4 bytes. A rare few systems arrange intin different ways but you're extremely unlikely to encounter them.
其他一些系统是 big-endian 并在另一个方向排列字节:* ((int*)d) == c * 22? + ?? * 21? + ?? * 2? + ??. 在这些系统中,你会发现,价值总是开始用35时十六进制打印。某些系统的大小int不同于 4 个字节。少数系统int以不同的方式排列,但您极不可能遇到它们。
Depending on your compiler and operating system, you may find that the value is different every time you run the program, or that it's always the same but changes when you make even minor tweaks to the source code.
根据您的编译器和操作系统,您可能会发现每次运行程序时该值都不同,或者当您对源代码进行微小调整时它总是相同但会发生变化。
On some systems, an intvalue must be stored in an address that's a multiple of 4 (or 2, or 8). This is called an alignmentrequirement. Depending on whether the address of chappens to be properly aligned or not, the program may crash.
在某些系统上,int值必须存储在 4(或 2 或 8)的倍数的地址中。这称为对齐要求。根据 的地址是否c正确对齐,程序可能会崩溃。
In contrast with your program, here's what happens when you have an intvalue and take a pointer to it.
与您的程序相反,当您拥有一个int值并获取指向它的指针时,会发生以下情况。
int x = 42;
int *p = &x;
-+----+----+----+----+----+----+-
| | x | |
-+----+----+----+----+----+----+-
^~~~~~~~~~~~~~~~~~~
| int
p
The pointer ppoints to an intvalue. The label on the arrow correctly describes what's in the memory cell, so there are no surprises when dereferencing it.
指针p指向一个int值。箭头上的标签正确地描述了内存单元中的内容,因此在取消引用时不会出现意外。
回答by Hyman
char c = '5'
A char(1 byte) is allocated on stack at address 0x12345678.
A char(1 字节)在堆栈上的地址 处分配0x12345678。
char *d = &c;
You obtain the address of cand store it in d, so d = 0x12345678.
您获取 的地址c并将其存储在 中d,因此d = 0x12345678。
int *e = (int*)d;
You force the compiler to assume that 0x12345678points to an int, but an int is not just one byte (sizeof(char) != sizeof(int)). It may be 4 or 8 bytes according to the architecture or even other values.
您强制编译器假定0x12345678指向 an int,但 int 不仅仅是一个字节 ( sizeof(char) != sizeof(int))。根据体系结构甚至其他值,它可能是 4 或 8 个字节。
So when you print the value of the pointer, the integer is considered by taking the first byte (that was c) and other consecutive bytes which are on stack and that are just garbage for your intent.
因此,当您打印指针的值时,通过取第一个字节(即c)和堆栈上的其他连续字节来考虑整数,这些字节对于您的意图来说只是垃圾。
回答by R.. GitHub STOP HELPING ICE
Casting pointers is usually invalid in C. There are several reasons:
在 C 中转换指针通常是无效的。有几个原因:
Alignment. It's possible that, due to alignment considerations, the destination pointer type is not able to represent the value of the source pointer type. For example, if
int *were inherently 4-byte aligned, castingchar *toint *would lose the lower bits.Aliasing. In general it's forbidden to access an object except via an lvalue of the correct type for the object. There are some exceptions, but unless you understand them very well you don't want to do it. Note that aliasing is only a problem if you actually dereference the pointer (apply the
*or->operators to it, or pass it to a function that will dereference it).
结盟。由于对齐考虑,目标指针类型可能无法表示源指针类型的值。例如,如果
int *本质上是 4 字节对齐,则强制转换char *为int *将丢失低位。别名。通常,除非通过对象的正确类型的左值,否则禁止访问对象。有一些例外,但除非你非常了解它们,否则你不想这样做。请注意,如果您实际取消引用指针(将
*或->运算符应用于它,或将其传递给将取消引用它的函数),则别名只是一个问题。
The main notable cases where casting pointers is okay are:
可以使用强制转换指针的主要值得注意的情况是:
When the destination pointer type points to character type. Pointers to character types are guaranteed to be able to represent any pointer to any type, and successfully round-trip it back to the original type if desired. Pointer to void (
void *) is exactly the same as a pointer to a character type except that you're not allowed to dereference it or do arithmetic on it, and it automatically converts to and from other pointer types without needing a cast, so pointers to void are usually preferable over pointers to character types for this purpose.When the destination pointer type is a pointer to structure type whose members exactly match the initial members of the originally-pointed-to structure type. This is useful for various object-oriented programming techniques in C.
当目标指针类型指向字符类型时。指向字符类型的指针保证能够表示指向任何类型的任何指针,并在需要时成功地将其返回到原始类型。指向 void (
void *) 的指针与指向字符类型的指针完全相同,只是不允许对其取消引用或对其进行算术运算,并且它会自动与其他指针类型相互转换而无需强制转换,因此指向为此,void 通常优于指向字符类型的指针。当目标指针类型是指向结构类型的指针时,其成员与原始指向的结构类型的初始成员完全匹配。这对于 C 中的各种面向对象的编程技术很有用。
Some other obscure cases are technically okay in terms of the language requirements, but problematic and best avoided.
就语言要求而言,其他一些晦涩的情况在技术上是可以的,但有问题,最好避免。
回答by Ole Dittmann
I suspect you need a more general answer:
我怀疑你需要一个更一般的答案:
There are no rules on casting pointers in C! The language lets you cast any pointer to any other pointer without comment.
在 C 中没有强制转换指针的规则!该语言允许您将任何指针转换为任何其他指针而无需注释。
But the thing is: There is no data conversion or whatever done! Its solely your own responsibilty that the system does not misinterpret the data after the cast - which would generally be the case, leading to runtime error.
但问题是:没有数据转换或其他任何操作!系统不会在转换后误解数据,这完全是您自己的责任 - 通常情况下会导致运行时错误。
So when casting its totally up to you to take care that if data is used from a casted pointer the data is compatible!
因此,当完全由您决定时,请注意,如果数据是从强制转换的指针中使用的,则数据是兼容的!
C is optimized for performance, so it lacks runtime reflexivity of pointers/references. But that has a price - you as a programmer have to take better care of what you are doing. You have to know on your self if what you want to do is "legal"
C 针对性能进行了优化,因此它缺乏指针/引用的运行时自反性。但这也是有代价的——作为一名程序员,你必须更好地照顾你正在做的事情。你必须自己知道你想做的事情是否“合法”
回答by gkovacs90
You have a pointer to a char. So as your system knows, on that memory address there is a charvalue on sizeof(char)space. When you cast it up to int*, you will work with data of sizeof(int), so you will print your char and some memory-garbage after it as an integer.
你有一个指向 a 的指针char。因此,正如您的系统所知,在该内存地址上有一个空间char值sizeof(char)。当您将其转换为 时int*,您将使用 的数据sizeof(int),因此您将在其后将字符和一些内存垃圾打印为整数。

