2011-12-23 90 views
2

这两行代码有什么区别?C指针语法

int *ptr = &x; 

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

我很新的C和指针的概念 - 已主要讲授Java的 - 所以只是有点困惑。

在此先感谢。

回答

3

void *用于标注C中的通用指针。
含义它可以指向任何类型。

因此,在第一种情况下,您使用指向int的指针,以便任何使用它的人都知道它正在操作整数。

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

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

+1

感谢您的回答。如果有的话,'*'的位置有什么不同? – bobble14988 2011-12-23 10:23:10

+4

'int * ptr'和'int * ptr'之间没有区别,它只是编写约定 – Zoneur 2011-12-23 10:33:49

2

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

void *q = &x只是将x的地址存储在q中,而不关心x指向的内容。然后int *p = q将该地址分配给其语义描述为其指向int的实体。

注意,在这种情况下,操作是安全的,因为xint型和pint *类型。如果您将q分配给类型的指针,例如double *,则不会如此。

1

两个陈述都是一样的,但第一个是首选,因为第二个是你摆脱危险的类型。

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

因此,

void* q = &x;

摆脱X

int* p = q; 

的类型,而这一次蒙上未知类型的整数指针。你最好把q表示为(int *)来表示你意识到了危险。

3

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; 
} 

Adapted from 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函数没有强制转换 - 好了,没有必要。所有的指针都是相同的大小,所以不需要做任何事情。