请查看以下func及其输出
void main()
{
Distance d1;
d1.setFeet(256);
d1.setInches(2.2);
char *p=(char *)&d1;
*p=1;
cout<< d1.getFeet()<< " "<< d1.getInches()<< endl;
}
班级Distance
通过setFeet
和setInches
获取其值,分别传递int
和float
个参数。它会通过getFeet
和getInches
方法显示值。
但是,此函数的输出为257 2.2
。为什么我会得到这些值?
答案 0 :(得分:14)
这是一个非常糟糕的主意:
char *p=(char *)&d1;
*p=1;
您的代码永远不应该对类的内部结构做出假设。例如,如果您的类具有任何虚函数,那么当您调用它们时,该代码会导致崩溃。
我只能断定你的Distance
课程如下:
class Distance {
short feet;
float inches;
public:
void setFeet(...
};
当你setFeet(256)
时,它将高字节(MSB)设置为1(256 = 1 * 2 ^ 8),将低字节(LSB)设置为0.当你赋值1
时对于char
对象地址的Distance
,你强制代表英尺的short
的第一个字节为1.在小端机器上,低字节位于较低的地址,因此最终得到short
,两个字节都设置为1,即1 * 2^8 + 1 = 257
。
在big-endian机器上,你仍然会得到值256,但这纯属巧合,因为你恰好在已经为1的字节上强制值为1。
但是,因为您正在使用未定义的行为,取决于编译器和编译选项,您最终可能会得到任何结果。 comp.lang.c中一个着名的表达式是,这种未定义的行为可能“导致恶魔飞出你的鼻子”。
答案 1 :(得分:2)
你是通过'p'指针非法重放内存。
该程序的输出未定义;因为您通过另一种类型的指针直接操作对象拥有的内存,而不考虑底层类型。
您的代码有点像这样:
struct Dist
{
int x;
float y;
};
union Plop
{
Dist s; // Your class
char p; // The type you are pretending to use via 'p'
};
int main()
{
Plop p;
p.s.x = 5; // Set up the Dist structure.
p.s.y = 2.3;
p.p = 1; // The value of s is now undefined.
// As you have scribbled over the memory used by s.
}
答案 2 :(得分:1)
基于给定代码的行为将是非常不可预测的。设置d1
数据的第一个字节可能会破坏vptr,编译器特定的内存,浮点值的符号/指数,或整数的LSB或MSB,这些都取决于Distance的定义。
答案 3 :(得分:0)
我假设你认为做* p = 1会在Distance对象中设置一个内部数据成员(可能是'feet')。它可能有用,但是(afaik)你不能保证脚部件位于对象的第一个地址,具有正确的大小(除非它的类型也是char)或它是否正确对齐。
如果你想这样做,为什么不将'脚'成员公开并做:
d1.feet = 1;
答案 4 :(得分:0)
void main()
。它不是标准的,它不会给您带来任何好处。在询问C或C ++问题时,它会让人们不再认真对待,并且可能导致程序无法编译或无法正常工作。
C ++标准在3.6.1第2段中说main()
总是返回int
,尽管实现可能会提供不同参数的变体。
这是打破习惯的好时机。如果你从使用void main()
的书中学习,那么这本书是不可靠的。如果仅供参考,请参阅另一本书。
答案 5 :(得分:0)
看起来你是编程新手,可以使用一些基本概念的帮助。
你正在寻找它,这很好,但是可能不是正确的地方。
祝你好运。答案 6 :(得分:0)
类的定义是
class Distance{
int feet;
float inches;
public:
//...functions
};
现在int脚将是00000001 00000000(2字节),其中零将占用Little Endian中的较低地址,因此char * p将为00000000 ..当你使* p = 1时,低位字节变为00000001所以int变量现在是00000001 00000001,正好是257!