-
Notifications
You must be signed in to change notification settings - Fork 160
/
Copy pathtypes.c
335 lines (253 loc) · 8.86 KB
/
types.c
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
324
325
326
327
328
329
330
331
332
333
334
335
/*
# types
*/
#include "common.h"
int main(void) {
/*
# Three major classes of types
There are three major classes of types:
- objects
- function
- incomplete
*/
/*
# Integer types
# Integer literals
Types that represent integer numbers are called integer types.
This classification is explicitly used on the C specification,
some operations or rule of the c language are only valid for integer types,
while others work also for floating point types.
`char` is also an integer type
*/
{
/* # char */
{
/* char has fixed size 1 byte: */
assert(sizeof(char) == 1);
/*
6.4.4.4 Character constants
*/
{
/* char literals are specified by single quotes */
char c = 'a';
/*
char literals are integers which happen to fit into char.
This has been changed in C++.
http://stackoverflow.com/questions/433895/why-are-c-character-literals-ints-instead-of-chars
*/
assert(sizeof('a') == sizeof(int));
/*
TODO is ASCII guaranteed:
- `assert('\0' == 0);`
- for the soures?
Seems not:
http://stackoverflow.com/questions/15251049/does-the-underlying-character-set-depend-only-on-the-c-implementation
> The value of an integer character constant containing more than one character (e.g.,
'ab'), or containing a character or escape sequence that does not map to a single-byte
execution character, is implementation-defined.
*/
assert('\0' == 0);
/*
WARN: multi-character character literals are obscure valid code, but the
byte ordering is undefined, so they are rarelly useful, and should be avoided.
gcc raises 4.8 warnings on -pedantic.
*/
/* assert('ab' == 'ab'); */
/* Can use the same backslash escapes as in strings. */
assert('\'' == 0x27);
assert('\n' == 0x0a);
}
}
/*
# short
Short has no specific literals, the only way is to typecast.
*/
{
{ short si = 1; }
{ short si = (short int)1; }
{ int i = 1; }
/* Lower case possible but bad, since l looks more like 1 than `L`.*/
{ long li = (long)1l; }
{ long li = (long)1L; }
}
#if __STDC_VERSION__ >= 199901L
/* # long long int */
{
{ long long lli = 8ll; }
{ long long lli = 8LL; }
}
#endif
/* ERROR: mixed cases not allowed */
/*{ long long lli = 8Ll; }*/
/* Short, long and long long are the same as the int versions: */
assert(sizeof(short) == sizeof(short int));
assert(sizeof(long) == sizeof(long int));
assert(sizeof(long long) == sizeof(long long int));
/*
# unsigned
C has unsigned versions of all built-in data types.
These basically have more or less double the maximum size
of the signed version, and are always positive.
You should always use unsigned sizes for quantities which must be positive such as:
- array indexes
- memory sizes (size_t)
As this will give clues to the compiler
and humans about the positive quality of your number
*/
{
/* Literals. */
{
{ unsigned char uc = (unsigned char)1; }
{ unsigned short usi = (unsigned short int)1u; }
{ unsigned int ui = 1u; }
{ unsigned int ui = 1U; }
{ unsigned long uli = 1lu; }
{ unsigned long uli = 1LU; }
{ unsigned long long ulli = 1llu; }
{ unsigned long long ulli = 1LLU; }
/* The following are not recommended unless you are into code obfsucation: */
{ unsigned long uli = 1Lu; }
{ unsigned long uli = 1lU; }
{ unsigned long long ulli = 1LLu; }
{ unsigned long long ulli = 1llU; }
/* ERROR: */
/*{ unsigned long long ulli = 1Llu; }*/
}
/*
# unsigned char
# signed char
# char vs unsigned char
For all integer types, `signed X` is the same as `X`.
`char` is the exception: there are *three* char types in C!
- `char`: unspecified if signed or not
- `signed char`
- `unsigned char`
http://stackoverflow.com/questions/2054939/is-char-signed-or-unsigned-by-default
*/
}
/* # Bases for integer literals */
{
/* # Hexadecimal */
{
assert(16 == 0x10 );
assert(16 == 0x10 );
assert(16 == 0x10l );
assert(16 == 0x10ll );
assert(16 == 0x10u );
assert(16 == 0x10ul );
assert(16 == 0x10ull);
/* Case does not matter. */
assert(0xaB == 0xAb );
}
/* Octal. */
{
assert(16 == 020);
}
/*
# Binary literals
No ANSI way, but exist as a GNU extension.
<http://stackoverflow.com/questions/18244726/why-doesnt-c-have-binary-literals>
*/
}
/*
# Integer representation
C does not fix the binary representation for signed integers,
it only states which properties represenations must have.
As an example, the C standard explicitly mentions that the following
representations (but there may be more) are compatible with the standard:
- 2’s complement
- 1’s complement
- signed magnitude
Unsigned representation however seems to be fixed at the canonical binary.
This is what allows bitmasks to work.
http://stackoverflow.com/questions/12125650/what-do-the-c-and-c-standards-say-about-bit-level-integer-representation-and-m
*/
/*
# Incomplete types
Can have pointeres to them, but not variables.
*/
{
extern int is[];
/* Undefined struct. */
struct S *s;
}
}
/* # Floating point types and literals */
{
/*
# float
Usually implemented as IEEE 754 32-bit float.
*/
{
float f1 = 1.23e-34f;
assert(1. == 1.0f);
assert(1.f == 1.0f);
assert(1e0f == 1.0f);
/* ERROR: there must be a dot without `e`. */
/*float f = 1f;*/
}
/*
# double
Usually implemented as IEEE 754 32-bit float.
*/
{ double d = 1.23; }
/*
# long double
Usually implemented as an 80-bit float, which is an extension allowed by IEEE.
In, IEEE requires the exponent to have as many bits as the next larger defined size,
which is 128-bit wth 15 bit exponent.
This leaves 64-bits for the seignificand.
sizeof usually says 128 because it is memory aligned.
*/
{
{ long double ld = 1.23l; }
{ long double ld = 1.23L; }
}
}
#if __STDC_VERSION__ >= 199901L
/*
# Boolean type
# _Bool
Aliased as `bool` in `stdbool.h`.
*/
{
_Bool b = 0;
}
#endif
#if __STDC_VERSION__ >= 199901L
#ifndef __STDC_NO_COMPLEX__
/*
# Complex types
# _Complex
Possibly added to C99 to help replace FORTRAN once and for all.
# Complex literals.
Not part of the language: defined in the stdlib. For this reason,
we have to cheat on complex literal together with the complex.h header.
# STDC_NO_COMPLEX
If defined the implementation may not have complex.h.
Therefore, it is possible to be compliant without it.
*/
{
{ float _Complex c; }
{ double _Complex c; }
{ long double _Complex c; }
/*
WARN: You must say `double _Complex` or `float _Complex`:
just `_Complex is not standard.
*/
{
/* _Complex c */
}
/*
# Complex integer types
Complex integer types are not specified in C.
GCC adds them as an extension.
*/
{
/*int complex zi = 1 + 1*I;*/
}
}
#endif
#endif
return EXIT_SUCCESS;
}