Skip to content

Commit a4e799b

Browse files
authored
Fix Issue 6583 - cast() operation not fully specified (#3502)
* added cast pointers * added pointer cast * added square brackets * white space * fix issue 6583 - cast() operation not fully specified * requested changes * whitespace * new paragraph * requested changes
1 parent 5c41a68 commit a4e799b

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed

spec/expression.dd

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,60 @@ $(GNAME CastExpression):
11001100
(foo) - p; // subtract p from foo
11011101
-------------
11021102

1103+
$(H4 $(LNAME2 cast_basic_data_types, Basic Data Types))
1104+
$(P For situations where $(DDSUBLINK spec/type, implicit-conversions, implicit conversions)
1105+
on basic types cannot be performed, the type system may be forced to accept the
1106+
reinterpretation of a memory region by using a cast.
1107+
)
1108+
1109+
$(P An example of such a scenario is represented by trying to store a wider type
1110+
into a narrower one:
1111+
)
1112+
1113+
-------------
1114+
int a;
1115+
byte b = a; // cannot implicitly convert expression a of type int to byte
1116+
-------------
1117+
1118+
$(P When casting a source type that is wider than the destination type,
1119+
the value is truncated to the destination size.
1120+
)
1121+
1122+
$(SPEC_RUNNABLE_EXAMPLE_RUN
1123+
-------------
1124+
int a = 64389; // 00000000 00000000 11111011 10000101
1125+
byte b = cast(byte) a; // 10000101
1126+
ubyte c = cast(ubyte) a; // 10000101
1127+
short d = cast(short) a; // 11111011 10000101
1128+
ushort e = cast(ushort) a; // 11111011 10000101
1129+
1130+
writeln(b);
1131+
writeln(c);
1132+
writeln(d);
1133+
writeln(e);
1134+
-------------
1135+
)
1136+
1137+
$(P For integral types casting from a narrower type to a wider type
1138+
is done by performing sign extension.
1139+
)
1140+
1141+
$(SPEC_RUNNABLE_EXAMPLE_RUN
1142+
-------------
1143+
ubyte a = 133; // 10000101
1144+
byte b = a; // 10000101
1145+
1146+
writeln(a);
1147+
writeln(b);
1148+
1149+
ushort c = a; // 00000000 10000101
1150+
short d = b; // 11111111 10000101
1151+
1152+
writeln(c);
1153+
writeln(d);
1154+
-------------
1155+
)
1156+
11031157
$(H4 $(LNAME2 cast_class, Class References))
11041158

11051159
$(P Any casting of a class reference to a
@@ -1144,6 +1198,74 @@ $(H4 $(LNAME2 cast_class, Class References))
11441198
(i.e. a reinterpret cast).
11451199
)
11461200

1201+
$(H4 $(LNAME2 cast_pointers, Pointers))
1202+
$(P Casting a pointer variable to another pointer type modifies the value that
1203+
will be obtained as a result of dereferencing, along with the number of bytes
1204+
on which pointer arithmetic is performed.
1205+
)
1206+
1207+
$(SPEC_RUNNABLE_EXAMPLE_RUN
1208+
-------------
1209+
int val = 25185; // 00000000 00000000 01100010 01100001
1210+
char *ch = cast(char*)(&val);
1211+
1212+
writeln(*ch); // a
1213+
writeln(cast(int)(*ch)); // 97
1214+
writeln(*(ch + 1)); // b
1215+
writeln(cast(int)(*(ch + 1))); // 98
1216+
-------------
1217+
)
1218+
1219+
$(P Similarly, when casting a dynamically allocated array to a type of smaller size,
1220+
the bytes of the initial array will be divided and regrouped according to the new
1221+
dimension.
1222+
)
1223+
1224+
$(SPEC_RUNNABLE_EXAMPLE_RUN
1225+
-------------
1226+
import core.stdc.stdlib;
1227+
1228+
int *p = cast(int*) malloc(5 * int.sizeof);
1229+
for (int i = 0; i < 5; i++) {
1230+
p[i] = i + 'a';
1231+
}
1232+
// p = [97, 98, 99, 100, 101]
1233+
1234+
char* c = cast(char*) p; // c = [97, 0, 0, 0, 98, 0, 0, 0, 99 ...]
1235+
for (int i = 0; i < 5 * int.sizeof; i++) {
1236+
writeln(c[i]);
1237+
}
1238+
-------------
1239+
)
1240+
1241+
$(P When casting a pointer of type A to a pointer of type B and type B is wider than type A,
1242+
attempts at accessing the memory exceeding the size of A will result in undefined behaviour.
1243+
)
1244+
1245+
$(SPEC_RUNNABLE_EXAMPLE_RUN
1246+
-------------
1247+
char c = 'a';
1248+
int *p = cast(int*) (&c);
1249+
writeln(*p);
1250+
-------------
1251+
)
1252+
1253+
$(P It is also possible to cast pointers to basic data types.
1254+
A common practice could be to cast the pointer to an int value
1255+
and then print its address:
1256+
)
1257+
1258+
$(SPEC_RUNNABLE_EXAMPLE_RUN
1259+
-------------
1260+
import core.stdc.stdlib;
1261+
1262+
int *p = cast(int*) malloc(int.sizeof);
1263+
int a = cast(int) p;
1264+
writeln(a);
1265+
-------------
1266+
)
1267+
1268+
11471269
$(H4 $(LNAME2 cast_array, Arrays))
11481270

11491271
$(P Casting a dynamic array to another dynamic array is done only if the

0 commit comments

Comments
 (0)