类型转换指向int的指针。

时间:2015-08-07 17:59:06

标签: c pointers

我无法理解这个程序的输出。 我得到的是,首先,指针p,q,r,s指向null。

然后,有一个类型转换。但是怎么样,输出结果是1 4 4 8。我的想法可能非常错误。所以,如果我错了,请纠正我。

int main()
{

    int a, b, c, d; 
    char* p = (char*)0; 
    int *q = (int *)0; 
    float* r = (float*)0; 
    double* s = (double*)0; 

    a = (int)(p + 1); 
    b = (int)(q + 1);
    c = (int)(r + 1);
    d = (int)(s + 1);

    printf("%d %d %d %d\n", a, b, c, d); 

    _getch();
    return 0; 
}

4 个答案:

答案 0 :(得分:3)

指针算术,在这种情况下,将一个整数值添加到指针值,以指向它的类型为单位前进指针值。如果你有一个指向8字节类型的指针,那么向该指针添加1将使指针前进8个字节。

只有当原始指针和相加的结果都指向同一个数组对象的元素,或者刚好超过它的末尾时,指针算法才有效。

C标准描述的方式是(N1570 6.5.6第8段):

  

添加或减去具有整数类型的表达式时   从指针开始,结果具有指针操作数的类型。如果   指针操作数指向数组对象的元素和数组   足够大,结果指向一个偏离的元素   原始元素使得下标的差异   结果和原始数组元素等于整数表达式   [...]
  如果指针操作数和结果都指向了元素   相同的数组对象,或者超过数组对象的最后一个元素,   评估不得产生溢流;否则,行为   是未定的。如果结果指向一个过去的最后一个元素   数组对象,不得用作一元*的操作数   被评估的运算符。

刚好超过数组末尾的指针有效,但您无法取消引用它。单个非数组对象被视为1元素数组。

您的程序有未定义的行为。您将1添加到空指针。由于空指针不指向任何对象,因此对它的指针运算是未定义的。

但编译器并不需要检测未定义的行为,并且您的程序可能处理空指针就像任何有效的指针值一样,并以相同的方式对其执行算术运算。因此,如果空指针指向地址0(这是保证,BTW,但它非常常见),那么添加1可能给你一个指向地址 N 的指针,其中 N 是它指向的类型的字节大小。

然后将结果指针转换为int(最好是实现定义,如果指针大于int则会丢失信息,并且可能会产生陷阱表示)并打印int值。在大多数系统上,结果可能会显示charintfloatdouble的大小,通常为1,4,4和8字节,分别为。

您的程序行为未定义,但它在您的系统上的实际行为方式是典型的,并不令人惊讶。

这是没有具有未定义行为的程序,它说明了同一点:

#include <stdio.h>
int main(void) {

    char c;
    int i;
    float f;
    double d;

    char   *p = &c;
    int    *q = &i;
    float  *r = &f;
    double *s = &d;

    printf("char:   %p --> %p\n", (void*)p, (void*)(p + 1));
    printf("int:    %p --> %p\n", (void*)q, (void*)(q + 1));
    printf("float:  %p --> %p\n", (void*)r, (void*)(r + 1));
    printf("double: %p --> %p\n", (void*)s, (void*)(s + 1));

    return 0; 
}

和我系统上的输出:

char:   0x7fffa67dc84f --> 0x7fffa67dc850
int:    0x7fffa67dc850 --> 0x7fffa67dc854
float:  0x7fffa67dc854 --> 0x7fffa67dc858
double: 0x7fffa67dc858 --> 0x7fffa67dc860

输出并不像程序的输出那么清晰,但如果仔细检查结果,可以看到向char*添加1会使其提前1个字节,int*float*乘4个字节,double*乘8个字节。 (除了char,根据定义,它的大小为1个字节,这些在某些系统上可能会有所不同。)

请注意,"%p"格式的输出是实现定义的,可能会也可能不会反映您可能期望的算术关系类型。我曾在系统(Cray矢量计算机)上工作,其中递增char*指针实际上会更新存储在64位字的高3位中的字节偏移量。在这样的系统上,除非你知道机器和编译器如何工作的低级细节,否则我的程序(以及你的程序)的输出将更难解释。

但是对于大多数用途,您不需要来了解这些底层细节。重要的是指针算法的工作原理与C标准中描述的一样。了解它在位级上的完成情况对于调试很有用(这几乎是%p的用途),但不一定要编写正确的代码。

答案 1 :(得分:1)

向指针添加1会将指针前进到适合指针类型的下一个地址。

当(null)指针+ 1重铸为int时,您实际上是在打印指针所指向的每种类型的大小。

printf("%d %d %d %d\n", sizeof(char), sizeof(int), sizeof(float), sizeof(double) );

几乎完全相同。如果你想只用1 BYTE 递增每个指针,你需要在递增它们之前将它们转换为(char *)以让编译器知道

搜索有关指针算术的信息以了解更多信息。

答案 2 :(得分:0)

您需要对指向原始数据类型的指针进行类型转换,而不是将它们类型转换为指针本身,然后使用*(间接)运算符间接指向该变量值。例如,(int)(p + 1);表示p;在这种情况下,指向常量的指针首先递增到内存中的下一个地址(0x1)。并且此0x1被强制转换为int。这完全有道理。

答案 3 :(得分:-1)

您获得的输出与每种相关类型的大小有关。当你这样做指针运算时,它会通过添加的值乘以基本类型大小来增加指针的值。这样做是为了便于正确访问数组。

由于您的计算机上charintfloatdouble的大小分别为1,4,4和8,因此当您为每个关联指针添加1。

编辑:

删除了我认为没有表现出未定义行为的备用代码,实际上已经这样做了。