David Brown <
david...@hesbynett.no> writes:
.
>
>A few compilers, such as gcc, actually documented that type-punning
>unions worked - most did not, though people expected them to support
>them. I've never been clear as to whether the C standards committee
>changed their mind to make type-punning fully defined, or if they simply
>changed the wording of the standard to make it less ambiguous.
>
Reading through the Unisys C compiler manual is interesting, due
to the radically different underlying architecture, for example
in the porting section:
The comparison of negative numbers with unsigned types may behave differently on
A Series systems than on other platforms. Platforms that store arithmetic values in
one's or two's complement form store the sign when assigning to an unsigned type.
On A Series systems, the sign is not stored when assigning to an unsigned type. On
A Series systems, comparing a negative value with the value in an unsigned type will
never be true unless the CHAR2 or UNSIGNED subordinate options of the PORT
compiler control option are used to emulate two's complement arithmetic on
unsigned types. Another workaround is to change negative literals to their one's
complement values (for example, -1 becomes 0xFF).
The representation of scalar types differs between A Series systems and other
platforms. On A Series systems, integer types are 6-bytes in length and start on word
boundaries. Any calculations that assume the size of an integer type to be anything
other than 6 bytes will result in problems when portation occurs.
long Ary[ (sizeof(SomeObject)+3) / sizeof(long)];
The addition of the numeric literal 3 to the size of the type of SomeObject assumes that
sizeof(long) returns 4. In A Series C, sizeof(long) returns 6, causing the calculation
to return unexpected results. The following code fragment illustrates how you can
avoid this type of portation problem:
struct{ unsigned short Type;
unsigned char SeqNum;
} Info;
char *InfoPtr = &Info;
seq = InfoPtr[2];
Using InfoPtr[2] to access SeqNum assumes that bytes 0 and 1 contain the structure
member Type and that byte 2 contains the structure member SeqNum. On A Series
systems, Type occupies bytes 0 to 5, and SeqNum occupies byte 6, which means that
InfoPtr[2] accesses the wrong data.
When a pointer is implicitly or explicitly cast from a pointer to an object of a given
alignment to a pointer to an object of a more strict alignment, the resulting pointer
may not be aligned with the original pointer. For example, casting a pointer to char to a
pointer to int causes the pointer index to be divided by 6 to change from character to
word units. The divide by 6 operation causes the pointer to int to point to the
beginning of the word. If the char pointer points to the middle of the word, the two
pointers do not point to the same data. To catch pointer alignment errors of this type
at run time, use the $BOUNDS(ALIGNMENT) compiler control option.
Two's complement arithmetic is used on many platforms. On A Series systems,
arithmetic is performed on data in signed-magnitude form. This can cause
discrepancies in algorithms that depend on the two's complement representation. For
example, C applications that use encryption algorithms to match data, such as
passwords, between client and server must perform the encryption the same way on
the client-end and the server-end. The differences between the two's complement
and signed-magnitude representation may result in different values when fragments
of data are extracted, encrypted, and reinserted into the data.
To obtain matching results, you can define macros that return arithmetic results in
two's complement form. The following example illustrates macros for two's
complement addition and subtraction:
#define tc_add(arg1, arg2) (((arg1) + (arg2)) & 0xFF)
#define tc_sub(arg1, arg2) (((arg1) + (0x100 - (arg2))) & 0xFF)
The macro errno is defined as an array indexed by the unique stack number of the
execution process when $SET CONCURRENTEXECUTION or
$SHARING=SHAREDBYALL. As a result, each client of a C library has a unique errno
location. [ed. Note stack number in this context is equivalent to task/process id]
Although each errno location starts at zero, the location is not reset to zero when a
client delinks from a library or when another client links with the same stack number.
In order to avoid this issue, the C library should explicitly set errno to zero before
calling a function that sets errno.
Note: The macro errno cannot be used as a declarator when
$CONCURRENTEXECUTION or $SHARING=SHAREDBYALL and any of the standard
heads have been included.