Len*_*mel 58 c++ language-features static-typing endianness
(我想这个问题可能适用于许多类型语言,但我选择使用C++作为例子.)
为什么没有办法写:
struct foo {
little int x; // little-endian
big long int y; // big-endian
short z; // native endianness
};
Run Code Online (Sandbox Code Playgroud)
指定特定成员,变量和参数的字节顺序?
我知道变量的类型不仅决定了用于存储值的字节数,还决定了在执行计算时如何解释这些字节.
例如,这两个声明每个都分配一个字节,对于两个字节,每个可能的8位序列都是有效值:
signed char s;
unsigned char u;
Run Code Online (Sandbox Code Playgroud)
但是相同的二进制序列可能会有不同的解释,例如11111111,在分配时指的是-1,而指定时指的是s255 u.当有符号和无符号变量涉及相同的计算时,编译器(主要)负责正确的转换.
在我的理解中,字节序只是同一原则的变体:基于关于存储它的存储器的编译时信息对二进制模式的不同解释.
在允许低级编程的类型语言中使用该功能似乎是显而易见的.但是,这不是C,C++或我所知的任何其他语言的一部分,我没有在网上找到任何关于此的讨论.
我会试着总结一下我在询问后的第一个小时内收到的许多评论中的一些内容:
此外,现在我意识到签名和字节序不是一个完美的类比,因为:
big int并little int会具有完全相同的数值范围.unsigned char(假设char有8位)130不能用a表示signed char.因此,改变某些变量的字节顺序永远不会改变程序的行为(除了逐字节访问),而签名通常会改变.
YSC*_*YSC 53
[intro.abstract]/1:本文档中的语义描述定义了参数化的非确定性抽象机器.本文档不要求符合实现的结构.特别是,它们不需要复制或模拟抽象机器的结构.相反,需要符合实现来模拟(仅)抽象机器的可观察行为,如下所述.
C++无法定义字节序限定符,因为它没有字节序的概念.
关于signness和endianness之间的区别,OP写道
在我的理解中,字节序只是相同原理[(符号)]的变体:基于关于存储它的存储器的编译时信息对二进制模式的不同解释.
我认为签名既有语义也有代表性1.这[intro.abstract]/1意味着C++只关心语义,并且从不解决签名数字应该在内存2中表示的方式.实际上,"符号位"仅在C++规范中出现一次,并引用实现定义的值.
另一方面,字节序仅具有代表性方面:字节序没有任何意义.
随着C++ 20,std::endian出现.它仍然是实现定义的,但让我们测试主机的endian,而不依赖于基于未定义行为的旧技巧.
1)语义方面:有符号整数可以表示零以下的值; 代表性方面:例如,需要保留一点来传达正/负符号.
2)同样,C++从未描述应如何表示浮点数,经常使用IEEE-754,但这是由实现做出的选择,无论如何由标准强制执行:"浮动的值表示点类型是实现定义的".[basic.fundamental]/8
Use*_*ess 37
除了YSC的答案之外,让我们来看看你的示例代码,并考虑它可能实现的目标
struct foo {
little int x; // little-endian
big long int y; // big-endian
short z; // native endianness
};
Run Code Online (Sandbox Code Playgroud)
您可能希望这将精确指定与体系结构无关的数据交换(文件,网络,等等)的布局
但这不可行,因为有些事情仍然没有说明:
little int32_t,big int64_t并int16_t分别,如果这就是你想要的#pragma或__attribute__((packed))或其他一些编译器特定的扩展或者,你可能只是想反映一些特定硬件的存储方式-但big与little此不覆盖所有的可能性(仅仅是两种最常见的).
因此,提案是不完整的(它没有区分所有合理的字节排序安排),无效(它没有实现它所规定的),并且还有其他缺点:
性能
从本机字节顺序更改变量的字节顺序应该禁用算术,比较等(因为硬件无法在此类型上正确执行它们),或者必须静默注入更多代码,创建本机有序的临时工具.
这里的论点不是手动转换为/从本机字节顺序更快,而是明确地控制它使得更容易最小化不必要的转换次数,并且更容易推断代码的行为方式,而不是转换是隐式的.
复杂
现在,为整数类型重载或专用的所有内容都需要两倍的版本,以应对传递非本机字节序值的罕见事件.即使这只是一个转发包装器(有几个转换器可以转换为原生顺序),但它仍然有很多代码没有明显的好处.
反对更改语言以支持这一点的最后一个论点是您可以轻松地在代码中执行此操作.更改语言语法是一件大事,并且不会像类型包装器那样提供任何明显的好处:
// store T with reversed byte order
template <typename T>
class Reversed {
T val_;
static T reverse(T); // platform-specific implementation
public:
explicit Reversed(T t) : val_(reverse(t)) {}
Reversed(Reversed const &other) : val_(other.val_) {}
// assignment, move, arithmetic, comparison etc. etc.
operator T () const { return reverse(val_); }
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6113 次 |
| 最近记录: |