Hallo, Christian! Hello, everybody!
According to Christian Bockermann:
The output depends on the internal representation of strings and integers in your particular Pascal compiler. The result you expected is okay for Borland Pascal and obviously for Think Pascal as well, but GNU Pascal uses a different scheme to represent strings and integers.
If you examine `SizeOf ( x.rec.name )' and `SizeOf ( x.rec.number )' you will see that they are 12 and 4, not 4 and 2. The "12" is because GPC's strings comply to the ISO-10206 standard for Extended Pascal which (a) requires that the "capacity" (maximum length) of the string is stored in the variable and (b) does not limit the length of the string to 255 characters. This way, we have an overhead of two integers instead of one byte in the string. The "4" is because GPC is a 32-bit compiler, so `Integer' has four bytes instead of two. (And `LongInt' has eight bytes instead of four.)
So you have to replace `0..47' by `0..127', and the expected result reads
1..4: the binary decoding of the capacity (3) of the string, like 11000000 00000000 00000000 00000000 5..8: the binary decoding of the current length (2) of the string, like 01000000 00000000 00000000 00000000 9..10: the binary decoding of the ascii-code of the characters in the string, like 10000010 01000010 11..12: some 16 random bits 01010100 00000000 13..16: the 32-bit decoding of the integer variable, like 10010000 00000000 00000000 00000000
Remarks:
* Intel processors store the least-significant byte first ("little-endian"), so `9' becomes 10010000 0 0 0, not 0 0 0 10010000. The Mac, AFAIK, has a 68k processor which does it vice versa ("big-endian").
* Recent beta versions of GPC reserve one additional byte in each string for appending a `chr ( 0 )' character for sake of compatibility to C - which is not yet used. In future versions, byte 11 will be zero, and only byte 12 will have random bits when the length of the string is `2'. (That's why the size of the string is 12, not 11.)
!! You have discovered a bug in GPC: The compiler had forgotten to store the capacity of the string in the variant record. I will fix it as soon as possible - thanks for the report.
To work around, manually assign `x.rec.name.capacity:= 3' before you assign a value to `x.rec.name'.
!! You have discovered yet another bug in GPC: Accessing the packed array does not work correctly. Below is a patch to `types.c' which fixes the problem for Linux on the PC. (It may cause alignment problems on the Alpha; I will have to check ...)
* It is planned for gpc-2.2 to implement that sort of strings used in Borland Pascal and Think Pascal as a new data type `ShortString'.
Does anybody know, what I did wrong ?
Nothing. :-)
Only one hint: Always avoid doing assumptions on the internal representation of data in your programs, if possible.
Is it possible in another way to access and change some bits of a string of any other variable with the use of GPC ?
Yes: GPC implements Borland's `absolute' directive:
Var Name: String ( 3 ); (* Extended Pascal wants `String ( 42 )', *) (* not `String [ 42 ]'. *)
Bits: packed array [ 0..95 ] of Boolean absolute Name;
This means that `Name' and `Bits' share the same location in memory.
But we do not want to rely on the internal structure of `Name', thus it is cleaner to write
Bits: packed array [ 0..BitSizeOf ( Name ) - 1 ] of Boolean absolute Name;
Then `Bits' will always have the correct size.
Other methods to access bits are
* Sets. A set is in fact an array of bits, indexed with the element type. Those bits whose indices are elements of the set are 1, the others are 0.
* Bit masking. You can apply the (bitwise) `and' operator to a pair of integer values. If you want, for instance, to check whether the third bit (i.e. bit number 2) in a given integer `k' is set, you can write:
if k and 8 = 0 then ...
To test the `n + 1'th bit (i.e. the bit number `n') use
if k and ( 1 shl n ) = 0 then ...
with `shl' being the "shift left" operator.
This is how packed arrays of Boolean as well as sets work internally.
Greetings - and thanks for the bug reports,
Peter
Dipl.-Phys. Peter Gerwinski, Essen, Germany, free physicist and programmer peter.gerwinski@uni-essen.de - http://home.pages.de/~peter.gerwinski/ [971005] maintainer GNU Pascal [971001] - http://home.pages.de/~gnu-pascal/ [971005]
8< ---- gpc.diff -------------------------------------------------------------
To apply this patch, cd to the GPC source directory (a subdirectory `p' of the GCC source directory) and type
patch -p1 < gpc.diff
--- ../../gpc-971112/p/types.c Thu Nov 6 17:52:11 1997 +++ types.c Sun Nov 16 19:13:46 1997 @@ -1895,23 +1908,26 @@ * shift operations here. */ unsigned HOST_WIDE_INT imask; + tree long_type = TREE_INT_CST_LOW (bits) >= HOST_BITS_PER_WIDE_INT / 2 + ? long_long_unsigned_type_node + : unsigned_type_node; tree mask; - tree host_bits_per_wide_int = - build_int_2 (HOST_BITS_PER_WIDE_INT, 0); - tree ull_ptr = build_pointer_type (long_long_unsigned_type_node); + tree half_bits_per_long_type = build_int_2 (TYPE_PRECISION (long_type) / 2, 0); + tree half_bytes_per_long_type = build_int_2 (TYPE_PRECISION (long_type) / (2 * BITS_PER_UNIT), 0); + tree ull_ptr = build_pointer_type (long_type); tree offset = build_binary_op (FLOOR_MOD_EXPR, index, - host_bits_per_wide_int, 0); - index = build_binary_op (TRUNC_DIV_EXPR, index, - host_bits_per_wide_int, 0); + half_bits_per_long_type, 0); + index = build_binary_op (FLOOR_DIV_EXPR, index, + half_bits_per_long_type, 0); imask = ((unsigned HOST_WIDE_INT) ~0) - >> (HOST_BITS_PER_WIDE_INT - TREE_INT_CST_LOW (bits)); + >> (TYPE_PRECISION (long_type) - TREE_INT_CST_LOW (bits)); mask = build_int_2 (imask, 0); mask = build_binary_op (LSHIFT_EXPR, mask, offset, 0); var_access = convert_array_to_pointer (var_access); var_access = convert (string_type_node, var_access); var_access = build_binary_op (PLUS_EXPR, var_access, build_binary_op (MULT_EXPR, index, - host_bits_per_wide_int, 1), 1); + half_bytes_per_long_type, 1), 1); var_access = convert (ull_ptr, var_access); var_access = build_indirect_ref (var_access, "packed array access"); var_access = build_binary_op (BIT_AND_EXPR, var_access, mask, 1);