转换指针 - 运行时有什么区别?

fel*_*eek 18 c pointers casting

请考虑以下小示例代码:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int *i;
    char *c1, *c2;

    i = malloc(4);

    *i = 65535;

    c1 = i;
    c2 = (char *)i;

    printf("%p %p %p\n", i, c1, c2);
    printf("%d %d", *c1, *c2);

    free(i);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我分配内存来存储一个指向的整数i.然后,我存储值65535(1111 1111 1111 1111)*i.我接下来要做的是让两个char*指针也指向整数.我做了两次,但是用两种不同的方式:c1 = i;c2 = (char *)i;.最后,我在屏幕上打印所有指针和所有值.这三个指针指向同一个地址,这两个值*c1*c2正确(-1) .

但是,编译器会在此行中生成警告:c1 = i;.生成警告是因为我没有使用(char *)强制转换进行分配.

我想问的是为什么编译器会生成此警告,因为我没有看到使用中的任何差异c1 = i ; 或c2 = (char *)i;.在这两种情况下,结果都是具有相同大小(以字节为单位)的相同地址.这是适用于所有类型转换,哪怕是一个(int *)演员,(float *)演员,(short *)演员表等他们都产生相同的值,但是编译器将只接受它没有一个警告,如果正在使用的演员阵容指针的类型.

我真的想知道为什么编译器要求该转换,即使结果总是相同的.

R S*_*ahu 33

当你使用:

c2 = i;
Run Code Online (Sandbox Code Playgroud)

编译器警告你int*要将类型赋值给char*.这可能是一个无意的错误.编译器警告你,如果它确实是一个无意的错误,你有机会修复它.

当你使用:

c2 = (char *)i;
Run Code Online (Sandbox Code Playgroud)

你告诉编译器你作为程序员知道你在做什么.

  • 关于最后一句,那就是理论; 在实践中,它更多地被视为不称职的程序员用来关闭他们不理解的错误(通常使用函数指针)的方法.相关:[如果你必须施展,你买不起](http://blogs.msdn.com/b/oldnewthing/archive/2009/10/23/9911891.aspx). (6认同)
  • @MatteoItalia:我认为"由不称职的程序员用来关闭他们不理解的错误"可能是"告诉编译器你作为程序员知道你在做什么"的适当子集.(仅仅因为无能的程序员*说*他们知道他们在做什么,这并不意味着......) (3认同)

eca*_*mur 17

你的程序无效; 除非使用强制转换,否则当指向的类型是不兼容的类型时,不允许在指针类型之间进行赋值.

6.5.4施法者

3 - 除了6.5.16.1的约束允许之外,涉及指针的转换应通过显式转换来指定.

编译器接受您的代码作为扩展,但另一个编译器可能拒绝您的代码,这样做是正确的.这就是编译器在省略强制转换时发出警告的原因.

  • @ecatmur:我没有机器的例子,但是我可以想象一个机器的原因,它可以在不同的内存块中存储不同大小的值.该假设机器必须编写不同的机器代码以通过演员表读取值.实际上,一些DSP不能存储任何小于16或32位的值,并且对于那些char访问必须读取整个值然后移位和屏蔽.所以是的,有时地址会在演员表上改变. (2认同)

Phi*_*lip 9

指向不同类型对象的指针可能在各自的大小和对齐方面有所不同:

§6.2.5/ 26类型

指向void的指针应具有与指向字符类型的指针相同的表示和对齐要求.同样,指向兼容类型的限定或非限定版本的指针应具有相同的表示和对齐要求.所有指向结构类型的指针都应具有相同的表示和对齐要求.所有指向union类型的指针都应具有相同的表示和对齐要求.指向其他类型的指针不需要具有相同的表示或对齐要求.

特别是,sizeof(char *)可能有不同的价值sizeof(int *).此外,char *可能有不同的对齐要求int *.因此,隐式演员会产生警告.这就是C标准包含以下准则的原因:

§6.5.4/ 1

除了6.5.16.1的约束允许之外,涉及指针的转换应通过显式转换来指定.

  • @ cruelcore1:不对.根据C标准,指向不同类型的指针可能在表示(读取:大小)和对齐方面有所不同. (8认同)

hac*_*cks 6

编译器只知道将泛型指针转换void *为任何指针,反之亦然.除了通用指针之外,它还希望在指针赋值之前进行转换以生成兼容类型的指针,并确定赋值是在知情的情况下完成的.