C指针语法

这两行代码有什么区别?

int *ptr = &x; 

 void* q = &x; int* p = q; 

我对C和指针的概念很新 – 主要是用Java教过 – 所以有点困惑。

提前致谢。

void *用于记录C中的通用指针。
意思是它可以指向任何类型。

所以在第一种情况下int *ptr = &x; 你使用指向int的指针,所以任何使用它的人都知道它正在操纵一个整数。

在第二种情况下, void* q = &x; 你通过gereric指针指向一个整数地址。
问题是不清楚这个指针引用的是什么类型。

因此,第一个和第二个示例具有相同的效果(在您的具体示例中)但是void *不能像这样使用。

void * q =&x;

可能值得理解事物如何在记忆中表现出来,这样你才能理解void*的含义。 指针是内存中包含内存中另一个位置的位置。 有关实际示例,请考虑以下代码:

 int x = 4; int* y = &x; void* z = &x; 

在我的64位系统上,我可以使用gdb来检查内存。 结果如下表所示:

 Address | Memory Value | C expression ================================================================================ 0x7fffffffdf8c | 0x04 0x00 0x00 0x00 | int x = 4; 0x7fffffffdf98 | 0x8c 0xdf 0xff 0xff 0xff 0x7f 0x00 0x00 | int* y = &x; 0x7fffffffdf90 | 0x8c 0xdf 0xff 0xff 0xff 0x7f 0x00 0x00 | void* z = &x; 

我们在这看到什么? 好吧, 0x7fffffffdf8c0x7fffffffdf90由值0x04占用,我平台上的所有零 – 整数都是4字节宽,顺序是小端,所以字节与人们期望读取的相反。 然后,我们看到接下来的8个字节被x的地址占用,而对于第二个指针也是如此。

因此,使用指针的过程是读取地址处的地址并使用它。 听起来你可能对这个概念很满意,所以继续:

指针的类型不会影响指针的大小 。 这是关键。 查看上面的指针值,它们实际上都是相同的大小。 这里的大小值是关于目标内存的 – 它指示编译器加载并操作一定量(字节数 – 类型的大小/宽度)的内存。

正如其他人所说, void*是“无类型的”。 相反,它只是一个指针 ,编译器/ C语言将无法支持您解除引用它,因为没有类型信息 – 没有办法安全地告诉您想要读取的目标地址有多少内存。

但是,这个事实有时很有用。 使用类型的想法是在代码中提供一致性 – 如果函数需要64位整数,则使用类型强制执行此要求,这样就不会引入错误。 但是,有时你不介意你得到什么类型。 在这些情况下,您的要求是“一些记忆。任何记忆!” – 我能想到的最好的例子是memcpy – 这可能有点像这样:

 void *memcpy(void * s1, const void* s2, size_t n) { char *r1 = s1; const char *r2 = s2; while (n) { *r1++ = *r2++; -n; } return s1; } 

改编自uclibc 。 在这里,变量类型根本不重要 – 在内部,函数决定以sizeof(char)类型操作内存( char通常但不总是字节宽)但它同样可以在uint64_t或其他值上操作。 这里所有类型都是控制从起始地址开始考虑的字节数作为类型的一部分。

为了给你另一个表,这里是一些类型大小的比较:

 Address of ptr | Type in code | Memory it "sees" when dereferenced =========================================================================== 0x7fffffffdf90 | unsigned 64-bit | 0x8c 0xdf 0xff 0xff 0xff 0x7f 0x00 0x00 0x7fffffffdf90 | unsigned 32-bit | 0x8c 0xdf 0xff 0xff 0x7fffffffdf90 | unsigned 16-bit | 0x8c 0xdf 0x7fffffffdf90 | unsigned 8-bit | 0x8c 0x7fffffffdf90 | void* | Doesn't know how wide it is. 

你可能想知道为什么libc函数中没有强制转换 – 嗯,没有必要。 所有指针大小相同,因此无需其他任何指针。

ptrp的效果在两种情况下都是相同的,因为void *指针保证可以在强制转换之间转换。

void *q = &x只是将void *q = &x的地址存储在q ,而不关心x指向的是什么。 int *p = q然后将此地址分配给一个实体,该实体的语义描述它指向一个int

请注意,在这种情况下,操作是安全的,因为x的类型为intp的类型为int * 。 如果你将q分配给类型的指针,比如说double * ,那就不会这样了。

两个语句都是相同的,但第一个是首选,因为在第二个语句中你正在摆脱危险的类型。

类型的主要目的是阻止您分配不兼容的变量,如苹果和汽车。

从而,

void* q = &x;

摆脱了x的类型

 int* p = q; 

并且这个将未知类型转换为整数上的指针。 您最好将q转换为(int *)以表示您已意识到危险。