forked from HowardHinnant/HowardHinnant.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathendian.html
323 lines (277 loc) · 7.82 KB
/
endian.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>endian</title>
<style>
p {text-align:justify}
li {text-align:justify}
blockquote.note
{
background-color:#E0E0E0;
padding-left: 15px;
padding-right: 15px;
padding-top: 1px;
padding-bottom: 1px;
}
ins {color:#00A000}
del {color:#A00000}
code {white-space:pre;}
</style>
</head>
<body>
<address align=right>
Document number: DxxxxR0<br>
<br/>
<br/>
<a href="mailto:[email protected]">Howard E. Hinnant</a><br/>
2016-08-21<br/>
</address>
<hr/>
<h1 align=center><code>endian</code>, Just <code>endian</code></h1>
<h2>Contents</h2>
<ul>
<li><a href="#Introduction">Introduction</a></li>
<li><a href="#Proposal">Proposal</a></li>
<li><a href="#Implementation">Implementation</a></li>
<li><a href="#Wording">Wording</a></li>
</ul>
<a name="Introduction"></a><h2>Introduction</h2>
<p>
An ancient, time-honored tradition among C++ programmers is detecting the
endian of their execution environment:
</p>
<blockquote><p>
<a href="http://stackoverflow.com/q/1001307/576911">Detecting endianness programmatically in a C++ program</a>
</p></blockquote>
<p>
There are many hacks that work <i>most</i> of the time. None of them seem bullet proof.
Few give the answer as a compile-time constant. And in every single case:
</p>
<blockquote><p><b>
The compiler knows the answer!
</b></p></blockquote>
<p>
It is a no-brainer for the committee to provide an API so that the programmer can query
the implementation for an answer to this common question.
</p>
<a name="Proposal"></a><h2>Proposal</h2>
<p>
Put into <code><type_traits></code>:
</p>
<blockquote><pre>
enum class endian
{
little = __ORDER_LITTLE_ENDIAN__,
big = __ORDER_BIG_ENDIAN__,
native = __BYTE_ORDER__
};
</pre></blockquote>
<p>
with appropriate constants for platforms that don't define <code>__BYTE_ORDER__</code>
et al. That's it. That's the entire proposal.
</p>
<p>
<u>Objection #1:</u> Some modern processors can switch endian at run time. How can this
be a compile-time constant?
</p>
<blockquote><p>
No operating system tolerates switching endian at run time once an application has
launched. Every compiler knows what endian it has to target.
</p></blockquote>
<p>
<u>Objection #2:</u> Where are the functions to translate scalars between native endian
and big or little endian?
</p>
<blockquote><p>
Those are good features to have. But they do not represent everything that is needed.
And they can more easily be built on top of <code>enum class endian</code> once it exists.
At a minimum we need <code>enum class endian</code> as soon as possible (1998 would be nice).
This proposal aims to get the minimum required functionality in as quickly as possible.
</p></blockquote>
<p>
<u>Objection #3:</u> I am quite sure that PDP endian is on the way back in. PDP is
neither big nor little endian. This proposal doesn't handle that!
</p>
<blockquote><p>
<ol>
<li>This proposal handles "mixed endian" today by ensuring that
<code>endian::native</code> equals neither <code>endian::big</code> nor
<code>endian::little</code>.</li>
<li>Today, no C++14 compiler targets a machine that is not big endian or little
endian.</li>
<li>If tomorrow we need another flavor of endian, a new member could easily be
added to <code>enum class endian</code> with no backwards compatibility problems
(e.g. <code>endian::pdp</code>).</li>
</ol>
</p></blockquote>
<p>
<u>How do I use this?</u>
</p>
<blockquote><p>
You can either build compile-time traits with this, or use it at run time. For example:
</p>
<blockquote><pre>
if (endian::native == endian::big)
// handle big endian
else if (endian::native == endian::little)
// handle little endian
else
// handle mixed endian
</pre></blockquote>
<p>
As another common example, here is a complete implementation of <code>hton</code>
and <code>ntoh</code> (except for the hard part):
</p>
<blockquote><pre>
template <class Integral>
constexpr
inline
std::enable_if_t
<
std::is_integral<Integral>{} &&
(1 < sizeof(Integral) && <b>std::endian::native != std::endian::big</b>),
Integral
>
hton(Integral x)
{
return reverse_bytes(x);
}
template <class Integral>
constexpr
inline
std::enable_if_t
<
std::is_integral<Integral>{} &&
(1 == sizeof(Integral) || <b>std::endian::native == std::endian::big</b>),
Integral
>
hton(Integral x)
{
return x;
}
static_assert(std::endian::native == std::endian::big ||
std::endian::native == std::endian::little,
"These aren't the endians you're looking for. Move along.");
template <class Integral>
constexpr
inline
std::enable_if_t
<
std::is_integral<Integral>{},
Integral
>
ntoh(Integral x)
{
return hton(x);
}
</pre></blockquote>
<p>
A <code>constexpr</code> implementation of <code>reverse_bytes</code> <i>is</i>
possible, and is left as an exercise for the reader.
</p>
</blockquote>
<p>
<u>Why not just a macro?</u>
</p>
<blockquote><p>
This API was chosen because there are a few times when a program needs to do
<i>more</i> than just query endianness. Sometimes a program needs to either
<i>declare</i> or <i>request</i> endianness. This API provides a universal way
of doing so. For example a fingerprinting hash object such as
<a href="https://en.wikipedia.org/wiki/SHA-2">SHA-2</a> traffics in big endian.
This might be advertised like:
</p>
<blockquote><pre>
class sha256
{
public:
static constexpr std::endian endian = std::endian::big;
// ...
</pre></blockquote>
<p>
The type <code>sha256</code> may need to meet a type concept that requires a public
nested value of type <code>std::endian</code> that specifies how input should be
preprocessed, or that specifies how some of the output is encoded. Details like this
are crucial for inter-machine communication.
</p></blockquote>
<a name="Implementation"></a><h2>Implementation</h2>
<blockquote><pre>
enum class endian
{
#ifdef _WIN32
little = 0,
big = 1,
native = little
#else
little = __ORDER_LITTLE_ENDIAN__,
big = __ORDER_BIG_ENDIAN__,
native = __BYTE_ORDER__
#endif
};
</pre></blockquote>
<p>
On the platform on which I'm writing this, this preprocesses to:
</p>
<blockquote><pre>
enum class endian
{
little = 1234,
big = 4321,
native = 1234
};
</pre></blockquote>
<a name="Wording"></a><h2>Wording</h2>
<ol>
<li>
<p>
Add to [meta.type.synop].
</p>
<blockquote><pre>
enum class endian
{
little = <i>see below</i>,
big = <i>see below</i>,
native = <i>see below</i>
};
</pre></blockquote>
</li>
<li>
<p>
Add a new section after [meta.logical]:
</p>
<blockquote>
<p>
<b>20.15.9 Endian [meta.endian]</b>
</p>
<p>
Two common methods of byte ordering in multibyte scalar types are big-endian and
little-endian in the execution environment. Big-endian is a format for storage
of binary data in which the most significant byte is placed first, with the rest
in descending order. Little-endian is a format for storage or transmission of
binary data in which the least significant byte is placed first, with the rest
in ascending order. This subclause describes the endianness of the execution
environment.
</p>
<pre>
enum class endian
{
little = <i>see below</i>,
big = <i>see below</i>,
native = <i>see below</i>
};
</pre>
<p>
<code>endian::little</code> shall not be equal to <code>endian::big</code>. If
the execution environment is big-endian, <code>endian::native</code> shall be
equal to <code>endian::big</code>. If the execution environment is
little-endian, <code>endian::native</code> shall be equal to
<code>endian::little</code>. Otherwise <code>endian::native</code> shall have a
value that is not equal to either of <code>endian::big</code> nor
<code>endian::little</code>.
</p>
</blockquote>
</li>
</ol>
</body>
</html>