Is this code well-defined behavior, in terms of strict aliasing?
_Bool* array = malloc(n);
memset(array, 0xFF, n);
_Bool x = array[0];
The rule of effective type has special cases for memcpy
and memmove
(C17 6.5 §6) but not for memset
.
My take is that the effective type becomes unsigned char
. Because the second parameter of memset
is required to be converted to unsigned char
(C17 7.24.6.1) and because of the rule of effective type, (C17 6.5 §6):
...or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one.
array
after the memset
call?array[0]
access therefore violate strict aliasing? Since _Bool
is not a type excluded from the strict aliasing rule (unlike character types).memset function is used to copy the characters to fill the memory blocks. Conversion of ‘int’ to unsigned char takes place in the memset function before copying them into the array. The function shows undefined behavior if the count of the number of characters is greater than the size of the destination array.
Return value: The memset () function returns str, the pointer to the destination string. Note: We can use memset () to set all values as 0 or -1 for integral data types also. It will not work if we use it to set as other values.
memset() is used to fill a block of memory with a particular value. The syntax of memset() function is as follows :
If n is greater than the size of the object pointed to by str, the behavior is undefined. str [] : Pointer to the object to copy the character. ch : The character to copy. n : Number of bytes to copy. Return value: The memset () function returns str, the pointer to the destination string.
memset
does not change the effective type. C11 (C17) 6.5p6:
The effective type of an object for an access to its stored value is the declared type of the object, if any. [ This clearly is not the case. An allocated object has no declared type. ]
If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value. [ this is not the case as an lvalue of character type is used by
memset
! ]If a value is copied into an object having no declared type using
memcpy
ormemmove
, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one. [ this too is not the case here - it is not copied withmemcpy
,memmove
or an array of characters ]For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access. [ therefore, this has to apply in our case. Notice that this applies to accessing it as characters inside
memset
as well as dereferencingarray
. ]
Since the values are stored with an lvalue
that has character type inside memset
, and not have the bytes copied from another object with lvalues of character type (the clause exists to equate memcpy
and memmove
with doing the same with an explicit for
loop!), it does not get an effective type, and the effective type of elements is _Bool
for those accessed through array
.
There might be parts in the C17 standard that are underspecified, but this certainly is not one of those cases.
array[0]
would not violate the effective type rule.
That does not make using the value of array[0]
any more legal. It can (and will most probably) be a trap value!
I tried the following functions
#include <stdio.h>
#include <stdbool.h>
void f1(bool x, bool y) {
if (!x && !y) {
puts("both false");
}
}
void f2(bool x, bool y) {
if (x && y) {
puts("both true");
}
}
void f3(bool x) {
if (x) {
puts("true");
}
}
void f4(bool x) {
if (!x) {
puts("false");
}
}
with array[0]
as any of the arguments - for the sake of avoiding compile-time optimizations this was compiled separately. When compiled with -O3 the following messages were printed:
both true
true
And when without any optimization
both false
both true
true
false
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With