C++ 17是否可以在大端平台上实现?

Lan*_*yer -1 c++ byte endianness language-lawyer reinterpret-cast

让我们看看以下代码:

int i = 10;
char c = reinterpret_cast<char&>(i);
Run Code Online (Sandbox Code Playgroud)

[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对象中包含的值.只要值ichar([expr]/4表示否则这是UB)可表示的范围内,变量c应初始化为具有相同的值.

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

如果您认为编译器可以轻松处理上面的代码以生成符合C++ 17标准所要求的代码,那么可以考虑将指针int指向指向i的指针char.这样的转换不会改变指针值,即它仍然指向int对象i,这意味着将间接运算符应用于具有以下L2R转换的指针应该如上所述,即int如果是,则获取对象的值按char类型表示.

在以下代码中

int i = 10;
f(reinterpret_cast<char*>(&i)); // void f(char*)
Run Code Online (Sandbox Code Playgroud)

如果编译器i不知道函数f将对其参数做什么,那么编译器是否应该调整某个偏移的地址?并且编译器也不知道将传递给函数的内容f.上面的代码和函数f在不同的翻译单元中.

例如,如果f取消引用指针以通过它读取值,它将获得该值,i如上所述.但它也可以用指向真实char对象的指针调用,因此f无法调整给定的指针.这意味着调用者应调整指针.但是,如果[basic.types]/3允许,f将指针memcpy复制sizeof(int)到这个大小的字符数组并返回另一个int对象会怎样?很难想象如何在这里调整指针来加工所需的(通过[basic.types]/3[conv.lval] /3.4)行为.

那么,如果现有的实现真的符合C++ 17标准,那么现有的实现是做什么的?

eer*_*ika 9

编辑:完全重写:你已经说服我标准被打破了.

...结果引用与源glvalue相同的对象,但具有指定的类型.


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

我同意字面解释可能会导致您做出的结论.

鉴于您的解释,reinterpret_cast(以及根据其定义的任何内容reinterpret_cast)变得毫无用处,并且不仅在BE系统上,而且在LE系统上也不可能实现(考虑非整数类型之间的重新解释char).因此,我不相信是预期的意思.这可以被视为缺陷报告的候选者.

混淆可能是由于表达式"包含在"中的值,"指示的对象""结果指向同一对象"的定义不够准确.澄清或重写部分或全部这些可能是有序的.

  • @LanguageLawyer获得6个downvotes是令人沮丧的,但由于这种情况而变得被动 - 激进并不能帮助你得到答案.:/ (5认同)
  • @BenVoigt理论上讲,它是指针可互换的对象,而不是类型.但实际上,它只能在带有类型标记指针表示的平台上产生差异(甚至不太可能). (2认同)

Kit*_*it. 5

[intro.object]/1表示对于非多态对象,"其中发现的值的解释取决于用于访问它们的表达式类型(Clause [expr])."

(重点是标准本身,而不是我的标准)

正如您所注意到的,在您的情况下,此类表达式的类型是char,因此编译器不需要将此值解释为某个对象类型的值int.

  • 我认为[https://timsong-cpp.github.io/cppwp/n4659/basic.life#5](https://timsong-cpp.github.io/cppwp/n4659/basic.life#5)说它适用于_any_对象.如果原始类型具有非平凡的析构函数,则可能在标准中的某处隐藏UB _并且在离开块之前不会重新创建原始类型的对象,但是我在这个主题中懒得搜索它. (2认同)