C ++ 17可在大端平台上实现吗?

时间:2019-01-13 13:46:16

标签: c++ byte language-lawyer endianness reinterpret-cast

让我们看下面的代码:

int i = 10;
char c = reinterpret_cast<char&>(i);

[expr.reinterpret.cast]/11

  

如果可以使用reinterpret_­cast将“指向T1的指针”类型的表达式显式转换为“指向T2的指针”类型,则可以将类型T1的glvalue表达式强制转换为“对T2的引用”类型。结果指向与源glvalue相同的对象,但是具有指定的类型。

因此,具有指定reinterpret_cast<char&>(i)类型的char左值是指int对象i

要初始化c,我们需要值,因此要应用从左值到右值的转换[conv.lval]/3.4

  

glvalue指示的对象中包含的值是prvalue结果。

L2R转换的结果是i对象中包含的值。只要i的值在char可表示的范围内([expr]/4表示否则为UB),则变量c应该被初始化为具有相同的值。值。

从实现POV来看,在小端平台上,可以通过读取i对象地址处的字节来轻松实现。但是,在大端平台上,编译器将必须添加偏移量以获取最低有效字节。或者,将整个int对象读入寄存器并屏蔽第一个字节,这在两个字节序上都是可以接受的。

如果您认为上面的代码可以很容易地被编译器处理以生成符合C ++ 17标准要求的代码,请考虑将指针指向指向int的指针i指向char的指针。这样的强制转换不会更改指针值,即它仍然指向int对象i,这意味着通过以下L2R转换将间接操作符应用于此类指针应具有如上所述的作用,也就是说,如果int类型可以表示的话,则获取char对象的值。

在以下代码中

int i = 10;
f(reinterpret_cast<char*>(&i)); // void f(char*)

如果编译器不知道函数i对其参数做些什么,编译器是否应该将f的地址调整一些偏移量?而且,编译器也不知道将传递给函数f的内容。上面的代码和函数f位于不同的翻译单元中。

例如,如果f取消引用指针以通过它读取值,则如上所述,它将获得i的值。但是它也可以使用指向实际char对象的指针来调用,因此f无法调整给定的指针。这意味着调用方应调整指针。但是如果f传递指向memcpy的指针以将sizeof(int)个字节复制到此大小的字符数组并按照{{3}的允许复制回另一个int对象,该怎么办? }?很难想象如何在此处调整指针以达到所需的行为(通过[basic.types]/3[basic.types]/3)。

那么,如果有确实符合C ++ 17标准的现有实现,那么现有的实现有什么作用?

3 个答案:

答案 0 :(得分:8)

编辑:完全重写:您已经使我确信该标准已被破坏。

  
    

...结果指向与源glvalue相同的对象,但是具有指定的类型。

  
     
     
    

glvalue指示的对象中包含的值是prvalue结果。

  

我同意直译可能会得出您的结论。

鉴于您的解释,reinterpret_cast(以及用reinterpret_cast定义的任何内容)变得无用,不仅在BE系统上,而且在LE系统上,也无法实施(请考虑在非整型和char)。因此,我不认为这是预期的含义。这可以被视为缺陷报告的候选者。

该混淆可能是由于对表达式“包含在”中的值“指示的对象” ”的准确定义不足导致的“ 。澄清或改写其中的一些或全部可能是有条理的。

答案 1 :(得分:5)

[intro.object]/1说,对于非多态对象,“在其中找到的值的解释取决于用于访问它们的表达式(Clause [expr])的类型。 “

(强调是标准本身,而不是我的)

您已经注意到,这种情况下的表达式的类型为char,因此编译器不需要将此值解释为int类型的某些对象的值。

答案 2 :(得分:-1)

  

但是,在大端平台上,编译器将必须添加偏移量以获取最低有效字节。或者,将整个int对象读入寄存器并屏蔽第一个字节,这在两个字节序上都是可以接受的。

只有当您传递i的值时,这才是正确的。但是,对于reinterpret_cast<char&>,您传递的是地址,因为引用只是指针的语法不同。因此,c将获得i的MSB值,只要0就是sizeof(int) > 1

您写的与以下内容没有区别:

int i = 10;
char c = *reinterpret_cast<char*>(&i);