C 指针语法
这两行代码有什么区别?
int *ptr = &x;
我
void* q = &x;
int* p = q;
对 C 和指针的概念非常陌生 - 主要是在 Java 中教授的 - 所以有点困惑。
提前致谢。
What is the difference between these two lines of code?
int *ptr = &x;
and
void* q = &x;
int* p = q;
I'm very new to C and the concept of pointers - having been taught primarily in Java - so just a little confused.
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
void *
用于表示 C 中的通用指针。这意味着它可以指向任何类型。
因此,在第一种情况
int *ptr = &x;
中,您使用指向int
的指针,因此任何使用它的人都知道它正在操作一个整数。在第二种情况下
void* q = &x;
您通过一个 Gereric 指针指向一个整数地址。问题是不清楚这个指针指向什么类型。
因此,第一个和第二个示例具有相同的效果(在您的具体示例中),但是像这样使用
void *
并不安全。void *
is used to note a generic pointer in C.Meaning it can point to any type.
So in the first case
int *ptr = &x;
you use a pointer to anint
so anyone using it knows it is manipulating an integer.In the second case
void* q = &x;
you point to an integer address via a gereric pointer.The problem is that it is not clear what type this pointer is refering to.
So the first and 2 examples have the same effect (in your specific example) but the
void *
is not safe to be used like this.了解事物在内存中的表示方式可能是值得的,这样您就可以理解
void*
的含义。指针是内存中的一个位置,其中包含内存中的另一个位置。对于实际示例,请考虑以下代码:在我的 64 位系统上,我可以使用 gdb 来检查内存。结果如下表所示:
我们在这里看到了什么?好吧,
0x7fffffffdf8c
到0x7fffffffdf90
由值0x04
和全零占据 - 我的平台上的整数是 4 字节宽,顺序是小端字节序,因此字节与人类期望读取的字节相反。然后,我们看到接下来的 8 个字节被 x 的地址占用,第二个指针也是如此。因此,使用指针的过程是读取某个地址处的地址并使用它。听起来您可能对这个概念相当满意,所以,继续:
指针的类型不会影响指针的大小。这是关键。查看上面的两个指针值,它们实际上都是相同的大小。这里的大小值涉及目标内存 - 它指示编译器加载并操作一定数量(字节数 - 类型的大小/宽度)的内存。
void*
,正如其他人所说,是“无类型的”。相反,它只是一个指针,编译器/C 语言将无法支持您取消引用它,因为没有类型信息 - 无法安全地知道目标有多少内存您想阅读的地址。然而,这个事实有时是有用的。使用类型的想法是为了在代码中提供一致性 - 如果函数需要 64 位整数,则使用类型会强制执行此要求,这样就不会引入错误。然而,有时您并不介意获得什么类型。在这些情况下,您的要求是“一些内存。任何内存!” - 我能想到的最好的例子是 memcpy - 它的工作原理可能有点像这样:
改编自 uclibc。在这里,变量类型根本不重要 - 在内部,函数决定以
sizeof(char)
类型操作内存(char
通常但不总是字节宽)但它同样可以对 uint64_t 或其他值进行操作。类型在这里所做的只是控制从起始地址开始有多少字节被视为类型的一部分。为了给您另一个表格,这里是一些类型大小的比较:
您可能想知道为什么 libc 函数中没有强制转换 - 好吧,没有必要。所有指针的大小相同,因此无需执行任何其他操作。
It's probably worth understanding how things are represented in memory so you understand the meaning of
void*
. A pointer is a position in memory containing another position in memory. For a real-world example, consider the following code:On my 64-bit system, I can use gdb to examine the memory. The results are as you see in the following table:
What do we see here? Well,
0x7fffffffdf8c
to0x7fffffffdf90
is taken up by the value0x04
and all zeros - integers on my platform are 4-bytes wide and the order is little endian, so the bytes are the opposite of what a human would expect to read. Then, we see the next 8-bytes are taken up by none other than the address of x, and likewise again for the second pointer.So the process of using a pointer is to read the address at an address and work with that. It sounds like you might be fairly happy with that concept as is, so, moving on:
The type of the pointer does not affect the size of the pointer. This is key. Looking at both your pointer values above, they are actually both the same size. The size value here talks about the target memory - it instructs the compiler to load and operate on a certain amount (number of bytes - the size/width of a type) of memory.
void*
, as others have said, is "typeless". Rather, it is just a pointer and the compiler/C language will not be able to support you dereferencing it, since there is no type information - there is no way to safely tell how much memory at the target address you want to read.However, this fact is sometimes useful. The idea of using types is to provide consistency in your code - if a function expects a 64-bit integer, using types enforces this requirement so that you don't introduce errors. Sometimes, however, you don't mind what type you get. In these cases, your requirements are "some memory. any memory!" - the best example of this I can think of is memcpy - which might work a little like this:
Adapted from uclibc. Here, the variable types do not matter at all - internally, the function decides to manipulate memory in
sizeof(char)
types (char
is usually but not always a byte wide) but it could equally have operated onuint64_t
or some other value. All the type does here is control how many bytes are being considered from the start address as part of the type.To give you another table, here's a comparison of some type sizes:
You might wonder why there are no casts in that libc function - well, there is no need. All pointers are the same size so nothing else needs to be done.
ptr
和p
的效果在这两种情况下是相同的,因为void *
指针保证在强制转换之间可转换。void *q = &x
只是将x
的地址存储在q
中,而不关心x
指向什么到。int *p = q
然后将此地址分配给一个实体,该实体的语义描述为它指向int
。请注意,在这种情况下,操作是安全的,因为
x
的类型为int
,而p
的类型为int *
。如果您将q
分配给类型为double *
的指针,情况就不会如此。The effect for
ptr
andp
is the same in both cases, since avoid *
pointer is guaranteed to be convertible between casts.void *q = &x
simply stores the address ofx
inq
, without caring whatx
is pointing to.int *p = q
then assigns this address to an entity whose semantics describe that it is pointing to anint
.Note that in this case the operation is safe because
x
is of typeint
andp
is of typeint *
. It wouldn't be so if you assignedq
to a pointer of type, say,double *
.两个语句是相同的,但是第一个语句是首选,因为在第二个语句中您将摆脱危险的类型。
类型的主要目的是防止您分配不兼容的变量,例如苹果和汽车。
因此,
void* q = &x;
摆脱了 x 的类型
,并将未知类型转换为整数上的指针。您最好将 q 转换为 (int *) 以表示您意识到危险。
Both statements are the same, but the first one is preferred as in the second one you are getting rid of the type which is dangerous.
The principal purpose of types is that they prevent you from assigning the variables which are not compatible, like apples and cars.
Thus,
void* q = &x;
gets rid of the type of x
and this one casts an unknown type to the pointers on integers. You should best cast q to (int *) to signify that you are aware of the danger.