2012-07-29 111 views
1

我来自C#和Java的背景,我似乎无法理解C++中使用指针进行投射的含义。C++类型使用指针投射

例如:

int x = 1; 
char c = *((char*)&x); 

它有什么作用?它对于什么有用?

+4

在C++中,你应该避免强制转换。投射是告诉编译器“不,不,你会认为这是错误的,但我确定我是对的”。在C++中,尽管总是让编译器正确无误。投射是一种抑制编译器错误的方法。所以基本上,为了某个特定目的而要求铸造,而不是一般铸造,这是更具建设性的。你的两个例子都应该在C++中完全避免。 – tenfour 2012-07-29 10:55:19

+0

你想知道如何使用指针来转换或者从你的例子中转换为char *和char const吗? – Rndm 2012-07-29 11:00:33

+0

我编辑了这篇文章,现在应该更清楚我的想法。 – UnTraDe 2012-07-29 11:00:55

回答

4

在这两个例子中,你都犯了错误,导致代码不能编译。所以我会假设你想做到以下几点:

int x = 1; 
char c = *((char*)&x); 

根据您的架构,c现在拥有的至少一方的价值或x最显著字节。在这个例子中,这可以是0或1(这实际上可以用来检测字节顺序)。

你的第二个例子不起作用,因为你试图忽略const导致非法操作/坏转换(这也被称为“const正确性”)。

编辑:关于你提到的有关评论“这是什么意思?”:

在表达式: &somevariable将返回somevariable地址。 *somevariable将假设somevariable的内容是实际值的地址,然后返回。

声明: datatype是一个正常的变量/对象。这是“按价值”通过的。 datatype&是一个参考。这与Java/C#中的正常变量完全相同,并且通过引用传递。 datatype*是一个指针。这只包含实际值所在的地址(见上文),并且基本上也是通过引用传递的。

实际的转换工作非常类似于Java/C#,但指针就是这样:它们指向实际值的位置。虽然这可能会让你感到困惑,但C/C++中的指针与Java/C#中使用的标准变量/引用非常相似。

看看这个:

MyClass x; // object of MyClass 
MyClass *x; // pointer to an object of MyClass - the actual value is undefined and trying to access it will most likely result in an access violation (due to reading somewhere random). 
MyClass *x = 0; // same as above, but now the default value is defined and you're able to detect whether it's been set (accessing it would essentially be a "null reference exception"; but it's actually a null pointer). 
MyClass &x = MyClass(); // creating a new reference pointing to an existing object. This would be Java's "MyClass x = new MyClass();" 
4

C++中的投射就像在Java中投射一样,没有涉及指针。

int x = 1; 
char c = (char) x; // Lose precision 

但是,你在这里做什么:

int x = 1; 
char *c = (char *)x; 

告诉编译器的x的值是一个字符的地址。它相当于

char *c; 
c = 1; // Set the address of c to 0x0000000000000001 

有你需要做的这个非常几次。

1

我以前用很多时间成语在指定的地址来访问硬件,自定义IO板。因此,例如在PIC(可编程中断控制器)来写重新设定标志(虚构代码):

#define PIC_LOC 0x1000 
#define PIC_ENABLE_PORT *((char*)(PIC_LOC+0x10)) 
#define BIT_ENABLE (1 << 3) 

... 
PIC_ENABLE_PORT |= BIT_ENABLE; 
... 
2

有在C++中两个根本不同的概念它们均有时被称为“铸造”:一种是转换,一个是重新解释

转换使用与现有对象“相同的值”创建一个新对象,但是该对象的类型不同。下面是一些例子:

实施例1:类型提升

// 1a: promote int to double to get the correct type of division 

int numerator = rand(), denominator = rand(); 
double d = double(numerator)/double(denominator); 

// 1b: convert int to double to achieve a particular argument deduction 

int n; 
template <typename T> void do_numeric_stuff(T x) { /* ... */ } 

do_numeric_stuff(double(n)); 

实施例2:衍生到基转换

struct B { }; struct D : B { }; 
D x; 

D * p = &x; // pointer to x 
B * q = p; // implicit conversion; may change the value! 


另一方面,重新解释允许我们把一个变量看作是另一个变量。关于唯一正确和有用的应用程序是系列化,以某种形式或另一种形式。

实施例3:序列

std::ofstream file("output.bin"); // output file 
char large_buffer[HUGE];    // in-memory buffer 

unsigned int n = get_data(); 

char const * p = reinterpret_cast<char const *>(&n); 
file.write(p, p + sizeof n);       // write the bytes of `n` 
std::copy(p, p + sizeof n, large_buffer);   // ditto 

std::copy(large_buffer + 17, large_buffer + 17 + sizeof n, 
      reinterpret_cast<char *>(&n)); // repopulate `n` from buffer 

标准说,它是未定义的行为通过指针是正确的类型(也称为“双关型”)的未访问的对象。虽然它是确定的存储对象的指针,也就是说,一个void*,然后再转换回来,并使用它,它是确定治疗浮动,就好像它是一个整数,等的唯一接受的方式访问一个对象就好像它是另一个对象一样,就是我所演示的一个对象,即将T类型的对象看作是一个数组char[sizeof(T)] —,也就是说,您可以访问每个对象的基础二进制表示。