77

K&R 没有仔细研究它,但他们使用它。我尝试通过编写一个示例程序来查看它是如何工作的,但它并不顺利:

#include <stdio.h> 
int bleh (int *); 

int main(){
    char c = '5'; 
    char *d = &c;

    bleh((int *)d); 
    return 0;  
}

int bleh(int *n){
    printf("%d bleh\n", *n); 
    return *n; 
}

它可以编译,但是我的打印语句会吐出垃圾变量(每次调用程序时它们都不同)。有任何想法吗?

4

5 回答 5

150
于 2013-06-23T12:54:59.210 回答
42
char c = '5'

A char(1 字节)在地址的堆栈上分配0x12345678

char *d = &c;

您获取 的地址c并将其存储在 中d,所以d = 0x12345678.

int *e = (int*)d;

您强制编译器假定它0x12345678指向一个int,但一个 int 不仅仅是一个字节(sizeof(char) != sizeof(int))。根据架构甚至其他值,它可能是 4 或 8 个字节。

因此,当您打印指针的值时,整数是通过获取第一个字节(即c)和堆栈上的其他连续字节来考虑的,这些字节对您的意图来说只是垃圾。

于 2013-06-23T12:03:13.813 回答
18

在 C 中强制转换指针通常是无效的。有几个原因:

  1. 结盟。由于对齐方面的考虑,目标指针类型可能无法表示源指针类型的值。例如,如果int *本质上是 4 字节对齐的,则转换char *int *会丢失低位。

  2. 别名。通常禁止访问对象,除非通过对象的正确类型的左值。有一些例外,但除非您非常了解它们,否则您不想这样做。*请注意,只有当您实际取消引用指针(将or->运算符应用于它,或将其传递给将取消引用它的函数)时,别名才是一个问题。

可以使用转换指针的主要值得注意的情况是:

  1. 当目标指针类型指向字符类型时。保证指向字符类型的指针能够表示指向任何类型的任何指针,并在需要时成功地将其往返返回到原始类型。指向 void ( void *) 的指针与指向字符类型的指针完全相同,只是不允许取消引用或对其进行算术运算,并且它会自动转换为其他指针类型,而无需强制转换,因此指向为此,void 通常比指向字符类型的指针更可取。

  2. 当目标指针类型是指向结构类型的指针时,其成员与最初指向的结构类型的初始成员完全匹配。这对于 C 中的各种面向对象的编程技术很有用。

就语言要求而言,其他一些晦涩的案例在技术上是可以的,但有问题,最好避免。

于 2013-06-23T12:45:31.397 回答
4

我怀疑您需要一个更一般的答案:

在 C 中没有关于强制转换指针的规则!该语言允许您将任何指针转换为任何其他指针而无需注释。

但问题是:没有数据转换或任何操作!系统不会在强制转换后误解数据,这完全是您自己的责任——通常情况就是这样,导致运行时错误。

因此,当完全由您决定时,请注意如果数据是从一个被转换的指针中使用的,那么数据是兼容的!

C 针对性能进行了优化,因此它缺乏指针/引用的运行时反射性。但这是有代价的——作为一名程序员,你必须更好地照顾你正在做的事情。如果你想做的是“合法的”,你必须自己知道

于 2013-06-23T12:22:36.120 回答
3

您有一个指向char. 因此,正如您的系统所知,在该内存地址上有一个空间charsizeof(char)。当您将其转换为 时int*,您将使用 的数据sizeof(int),因此您将在其后将 char 和一些内存垃圾打印为整数。

于 2013-06-23T12:02:55.447 回答