-
Notifications
You must be signed in to change notification settings - Fork 160
/
Copy pathtypecast.c
292 lines (224 loc) · 7.19 KB
/
typecast.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
/*
# Conversions
# typecast
C99 6.3 "conversions"
Transformation of one datatype to another.
Can be done either implicitly or explicitly via a typecast operator.
Some convertions may are allowed by the standard implicitly,
but generate compiler warnings when done implicitly because in practice
they should almost never be used.
Some convertions are not allowed by the standard
and should always generate compilation errors.
Typecasts only transform the data:
it seems that it is not possible to change the type of a variable itself:
http://stackoverflow.com/questions/2822795/how-i-change-a-variable-of-a-type-to-another-one-in-c
*/
#include "common.h"
int main(void) {
/*
# Implicit typecasts done on operations
The standard specifies which operations generate which typecasts.
*/
{
/* On assignment, the value is cast to the type of the variable assigned to. */
{
int i;
/* A typecast to int is done because `i` is `int`. */
i = 0.1;
/* SAME: */
i = (int)0.1;
assert(i == 0);
}
/*
If an operation involves an integer type and a floating type,
TODO the integer type is cast to the floating type.
*/
{
assert(1/2 == 0);
assert(1/2.0 == 0.5);
/* Typecasts happen on the same order that the operations are evaluated. */
assert(2.0*(1/2) == 0.0);
assert((2.0*1)/2 == 1.0);
}
/*
If an operation involves a smaller integer type and a larger integer type
TODO the smaller type is first cast to the larger type
*/
{
assert((char)CHAR_MAX + 1 == ((int)(char)CHAR_MAX + 1));
}
}
/*
# Negative literals
There are none.
The `-` sign is an unary minus operator and creates an expression.
It works out in the end because `1` in `-1` is a signed type,
so the unary minus works fine on int.
*/
{
assert(-1 == -(1));
}
/*
# unsigned to signed
# signed to unsigned
6.3.1.3
*/
{
/* Signed to unsigned: always OK. */
{
/* OK: can be represented. */
{
assert(((unsigned char)127) == ((char)127));
}
/* OK: to unsigned that cannot be represented wraps around. */
{
assert(((unsigned char)-1) == UCHAR_MAX);
}
}
#ifdef IMPLEMENTATION_SIGNAL
/*
Unsigned to signed is implementation defined, or implementation-defined signal.
GCC 4.8 x86 does 2's complement.
*/
{
printf("(char)UCHAR_MAX = %d\n", (char)UCHAR_MAX);
}
#endif
}
/*
# float to int
# int to float
# typecasts between integer and floating point types
C99 6.3.1.4 Real floating and integer
*/
{
/* float to int rounds towards 0. */
{
assert((int)0.5 == 0);
assert((int)-0.5 == 0);
}
/*
int to float can cause loss of precision if the int does not fit
in the fp mantissa.
Implementations define if they will round to the nearerst
larger or smaller float.
*/
#ifdef UNDEFINED_BEHAVIOUR
/*
If the float does not fit in an int, undefined behavior.
*/
{
/* Integral part too large. */
printf("(int)1e1023L = %d\n", (int)1e1023L);
/*
Negative integer part cannot be represented by unsigned types:
http://stackoverflow.com/questions/10541200/is-the-behaviour-of-casting-a-double-to-unsigned-int-defined-in-the-c-standard
Setting it to 0 is a common behavior.
*/
printf("(unsigned int)-1.1 = %u\n", (unsigned int)-1.1);
/*
Infinities and NAN
http://stackoverflow.com/questions/3986795/casting-float-inf-to-integer
*/
printf("(int)NAN = %u\n", (int)NAN);
}
#endif
}
/* Array to pointer of same type: */
{
int is[] = {0, 1, 2};
int *is2 = is;
assert(is2[0] == 0);
}
/*
# Integer to pointer.
Implementation defined.
http://stackoverflow.com/questions/9372936/can-we-assign-a-value-to-a-given-memory-location
*/
/*
# Implicit operator typecasts
# Usual arithmetic conversions
C99 6.3.1.8 "Usual arithmetic conversions"
Operators are like functions, but they have one extra piece of magic:
- the types of their inptus are not specified
- they can be "overloaded"
So unlike functions, we need magic rules for how to convert incompatible types.
*/
{
}
/*
# void typecast
It is however possible to cast any type to void.
But that cannot have any effect since you cannot set the result to a variable.
It can however be used to avoid unused variable warnings.
*/
{
/*
# Unused function arguments
- avoid compiler warnings
- document intent to developpers
<http://stackoverflow.com/questions/4647665/why-cast-an-unused-function-parameter-value-to-void>
Why would a function not use a parameter in real life:
- callbacks with fixed signature for which you don't need some parameters
- macros that can be turned on or off. In particular, remember that `assert()` is a macro
and can be toggled with `NDEBUG`.
*/
{
int i = 0;
(void)i;
i = 1;
}
/*
# Unused return value
- avoid compiler warnings
*/
}
/* */
{
}
/* # Impossible typecats */
{
/* Certain typecasts always generates compilation errors. */
/* Implicit pointer to int is impossible: */
/*
{
int* ip;
int i;
i = ip;
}
*/
/* Pointer to float is impossible even with explicit typecast: */
/*
{
int* ip;
float f;
f = (float)ip;
}
*/
/* Pointers of different types, */
/* even if types for which data can be converted like floats and doubles: */
/*
{
float* fp;
double* dp;
dp = fp;
}
*/
/* Array to array of different size: */
/*
{
int is1[1];
int is2[2];
is2 = (int[])is1;
}
*/
}
/*
# Typecast between two struct types
- http://stackoverflow.com/questions/3766229/casting-one-struct-pointer-to-other-c
- http://stackoverflow.com/questions/27127914/why-is-this-implicit-conversion-between-different-pointer-types-valid?lq=1
- http://stackoverflow.com/questions/10998639/is-it-possible-to-cast-struct-to-another
- http://stackoverflow.com/questions/8416417/nested-structs-and-strict-aliasing-in-c
*/
return EXIT_SUCCESS;
}