2

用于读取类对象(这里“艺术”是对象的名称)。我必须遵循以下代码filin 是输入和输出流。

filin.write((char*)&arts,sizeof(arts));
filin.read((char*)&arts,sizeof(arts));

你能解释一下这些。

  1. 为什么我们通过添加 (char *) 来键入 caste 以及为什么要添加到字符指针。

  2. 为什么在艺术之前添加 & 符号?

  3. 为什么要在最后添加 sizeof(arts) ?

4

5 回答 5

3

为什么我们通过添加 (char *) 来键入 caste 以及为什么要添加到字符指针。

char是一个错误的名字。这是一个谎言——它应该被调用byte,因为它就是:一个字节。您正在使用的readandwrite函数在字节缓冲区上工作——这是为了使它们成为通用的,即与任意类型一起工作(尽管这也是一个谎言)。

为什么在艺术之前添加 & 符号?

&获取对象的内存地址。通过写入(char*) &obj,我们有效地获取(地址)位于给定对象下的字节缓冲区——换句话说,以字节为单位的对象表示。

为什么要在最后添加 sizeof(arts) ?

sizeof(obj)告诉我们obj内存有多大——即它在字节缓冲区中占用了多少字节。给定起始地址(见前一点)和大小,我们可以完全描述对象在内存中的物理存在,我们可以使用它来将对象从主内存传输到文件中,反之亦然。

然而,正如我之前所说,这是一个谎言。C++ 实际上有许多类型的对象不支持这种复制它们的内存,因为这些对象实际上对它们所在的内存做出了假设。在最简单的情况下,它们包含一个指针成员,在复制字节表示之后对象,仍然指向旧位置,因此不再有用:

struct some_class {
    some_class* self;

    some_class() : self(this) { }
};

这个类有一个成员——<code>self——指向它自己。逐字节复制此类的实例将破坏此标识并使对象无用(复制后副本的self成员仍将指向原始对象,而不是副本)。

这种逐字节复制也称为浅拷贝——与可以正确复制上述指针的深拷贝相反。

您显示的代码在 C++ 中通常不安全。事实上,它存在的问题比我迄今为止提到的还要多,而且在大多数情况下,对象的(反)序列化有更好的选择。

于 2013-03-14T18:28:34.857 回答
2

回答您的问题:

1 -writeread取一个char指针 ( char *)。这意味着它一个字节一个字节writeread工作,并且读取或写入与函数的第二个参数给出的字节数完全相同的字节数。

2-&address of。这意味着您正在获取 的地址arts,然后将地址转换为char指针作为(char*)&arts

3 -sizeof()返回其参数的长度(长度是指一个实例在内存中占用的大小)。在这种情况下,您会得到 和 的大小,arts告诉write和,或read有多少位。writeread

于 2013-03-14T18:15:20.203 回答
2

首先,&操作员获取您的艺术品的指针。假设您的对象arts是类型Foo

Foo arts;

然后&arts是类型Foo*

您代码中的方法write()似乎处理字节数组(通常需要通过网络传输或写入文件),因此它使用指向char(写为char*)的指针,因为类型char的大小为 1 字节,(嗯,在我知道的任何平台上),因此,如果您从 char 指针中添加或减去,您可以将指针前进或倒退该字节数(在 C++ 中,指针算术以对象字节大小的倍数进行) .

当您转换 fromFoo*时,char*您实际上是在告诉编译器将该指针视为 1 字节的倍数,而不是对象完整大小的倍数。这是处理字节数组的函数的习惯做法,就像你的write()and read()函数中的情况一样。

最后,在第一个参数中,您只传递了一个指针,一个内存地址。因此,要让函数write()知道它必须从指针读取多少字节,您必须传入对象的长度(第二个参数)。该运算符sizeof(arts)在编译时转换为对象的字节大小arts(它也可以采用类型,因此如果是 的类型sizeof Foo,则写入将是等效的)。Fooarts

于 2013-03-14T18:22:42.893 回答
2

从第二个问题开始更容易。运算符 & 只是返回一个指向内存中对象的指针。然后我们将指向arts对象的指针转换为指向char的指针。Char 具有特定机器上最小可寻址内存单元的大小,它可以是 8 位(最常见),越来越少。我们也称它为“字节”。最后我们调用 sizeof 函数,它返回对象的大小,表示为存储该对象所需的最小内存单元(在我们的例子中是字符)的数量。在该函数接收指向内存中某个位置的指针以及要写入或读取的字节数之后。它需要知道的一切。

于 2013-03-14T18:29:29.313 回答
1

您发布的代码将对象存储在流中,然后从流中检索它。让我们把代码分成几块。

filin.write((char*)&arts,sizeof(arts));

首先,让我们检查一下 write 方法的签名。我猜,它看起来类似于以下内容:

stream::write(char * input, int size)

所以流对象需要一个指向内存中某个位置的指针,size从那里获取字节并存储。

现在,让我们将您的命令与此签名进行比较。input是 (char*)&arts。您有arts某种类型的对象,并且想要存储它。input必须是指向内存中存储对象的指针,因此您可以使用&运算符检索它:&arts。但是,该方法期望input是 a char*(意味着更多的是指向字节的指针,char 不仅在您想要处理字符时使用,而且在您想要处理字节的地方使用),但您的指针不是char *. 这就是进行类型转换的原因:指向arts类型的指针被转换为指向 a 的指针char *。它的值保持不变,但现在编译器知道,知道你在做什么。

接下来,有一个大小参数告诉流类消耗多少字节。由于您要存储艺术对象,sizeof(arts)因此调用 a 来验证其大小。

于 2013-03-14T18:22:52.017 回答