1

我正在研究 C++ 中的铸造,之后的代码对我来说很神奇。

#include <iostream>
using namespace std;

class Base {
public:
virtual void f() { }
};

#define SOME_VALUE 8

int main() {
cout << SOME_VALUE <<endl;
getchar();
}

输出为:8

代码很简单,但是什么类型的 SOME_VALUE 呢?int、double 还是 char?

之后更复杂:

#include <iostream>
using namespace std;

class Base {
public:
virtual void f() { }
};

#define SOME_VALUE 8
int main() {
cout << (Base*)SOME_VALUE-SOME_VALUE <<endl;
getchar();
}

输出为:FFFFFE8

按照这段代码,我可以理解 SOME_VALUE 是数字类型。我还测试了 sizeof(SOME_VALUE) 并且输出是 4。但是如果 SOME_WHAT 是数字,它如何更改为对象指针?以及对象指针如何减去整数?

4

3 回答 3

5

#define是一个预处理器命令。它在代码编译之前被评估。所发生的只是主函数中的 SOME_VALUE 将其文本替换为 SOME_VALUE 定义为的文本。那是8。

SOME_VALUE 本身没有 C++ 类型,因为它只存在于预处理之前。预处理后 SOME_VALUE 将不存在于 C++ 程序中,您将只有一个字面值 8,它是一个 int。

对于第二个问题,Base* 的转换使用 C 样式转换。只需将要转换的内容的原始内存视为目标类型,就可以将任何内容转换为任何内容。因此,如果正在转换的内存与目标类型不匹配,则可能会非常危险。对于 C++,我建议使用 static_cast 或 reinterpret_cast 来更明确地说明正在转换的内容。

我认为 (Base*)SOME_VALUE 最终会成为指向内存地址 8 的 Base*。所以,这是一个指向从内存中第 8 个字节开始的 Base 对象的指针。内存中的位置 8 可能没有 Base 对象,因此它实际上不是很有用。然后“- 8”去掉Base*类型大小的8倍。在 32 位计算机上,指针是 32 位或 4 字节。因此,8 - (4*8) = -24 十进制,即十六进制的 FFFFFFE8。

如果您想知道为什么计算机将负数表示为大数,那是另一个问题。从这里开始:http ://en.wikipedia.org/wiki/Signed_number_representations

于 2012-05-26T09:45:42.677 回答
2
cout << (Base*)SOME_VALUE-SOME_VALUE <<endl;

基本上是一种(可怕的)做法:

Base* b = 8;
b = b - 8;

8 将默默地乘以 Base 的大小(所以你减去 8 个基本插槽,而不是 8 个)。

指针通常是无符号的,所以发生的是无符号指针正在环绕。

0xFFFFFFE8 是 4294967272 或(假设 4 字节 unsigned int 通常环绕)8 - 24。

此外,您永远不应该在实际代码中这样做。将任意值分配给指针肯定会以火热的爆炸结束。

一个更容易理解的情况可能是这样的:

int* p = (int*) 24;
p -= 4; //like ((char*) p) - 4 * sizeof(int)

对于 4 字节整数, 的值p将是 8,因为 24 - 4 * sizeof(int) = 24 - 4 * 4 = 24 - 16 = 8。

于 2012-05-26T09:45:55.233 回答
2

SOME_VALUE是一个宏——它没有类型。 8然而,是一个整数。

使用#define SOME_VALUE ((Base*)8),如果您想SOME_VALUE始终表现得像Base*.

于 2012-05-26T09:46:53.913 回答