Date: Fri, 07 Aug 2020 08:41:45 +0200
Am 07.08.2020 01:12, schrieb Roman Babinicz via Std-Discussion:
> On 06/08/2020 03:47, Jason McKesson via Std-Discussion wrote: On Wed, Aug 5, 2020 at 1:58 AM Roman Babinicz via Std-Discussion
> <std-discussion_at_[hidden]> wrote:
>
> enum class mybyte : unsigned char{};
> using T1 = mybyte;
> auto ptr = new T1 [100];
> *(ptr+10) = static_cast<T1>(50);
> delete []ptr;
>
> Is this well formed way of accessing object via glvalue pointer
> (as in basic.lval#11.3) ?
>
> Because for some other types T1, e.g. for int, one possible reading of
> standard is that this is UB and you need to memcpy the buffer into a new
> location first (and even more likelly needed for non-fundamental types
> in T1).
> I don't understand what exactly would be ill-formed about this. So
Thanks, and now for following example (this is the issue I should has
posted first)
enum class mybyte : unsigned char{};
using T1 = mybyte;
auto buf = new T1 [100];
unsigned char * ptr = reinterpret_cast< unsigned char * > ( buf ) ;
*(ptr+10) = 50;
delete []buf;
so nowe we access enum objects via the unsigned char (pointer) that
happens to be the underlying type, but is that enough to avoid need for
memcpy?
Further question would be: for which T1 types you need to first memcpy
it?
> long as `T1` is a type which is default constructible and `T1` can be
> constructed from the integer literal 50, this code is fine. At no
> point are you reading any values as bytes. The fact that `unsigned
> char` is involved is essentially irrelevant.
>
> ptr is a pointer to an array of 100 `T1`s. So adding `10` to `ptr` is
> well-defined; it points to the 10th element (zero-based) of the array.
> `ptr + 10` is a valid pointer, and it is a pointer of that points to
> the type `T1`. It is also a pointer to an object of type `T1`. `T1` is
> the dynamic type of the object being pointed to, so [basic.lval/11.1]
> is satisfied.
>
> There is no "reading values as bytes" happening here.
Is there any particual reason why you are trying to avoid memcpy here?
While not guaranteed by the standard, pretty much any modern compiler is
going to produce the same code here whether you are going to use memcpy
or directly cast.
I've confirmed this on a project a few years ago, where we were trying
to enable strict-aliasing rules. So there should be no difference at
runtime between this:
int32_t readInt(char* data)
{
return *reinterpret_cast<int32_t*>(data);
}
and the standard-conformant way:
int32_t readInt(char* data)
{
int32_t out;
memcpy(&out, data, sizeof(int32_t));
}
> On 06/08/2020 03:47, Jason McKesson via Std-Discussion wrote: On Wed, Aug 5, 2020 at 1:58 AM Roman Babinicz via Std-Discussion
> <std-discussion_at_[hidden]> wrote:
>
> enum class mybyte : unsigned char{};
> using T1 = mybyte;
> auto ptr = new T1 [100];
> *(ptr+10) = static_cast<T1>(50);
> delete []ptr;
>
> Is this well formed way of accessing object via glvalue pointer
> (as in basic.lval#11.3) ?
>
> Because for some other types T1, e.g. for int, one possible reading of
> standard is that this is UB and you need to memcpy the buffer into a new
> location first (and even more likelly needed for non-fundamental types
> in T1).
> I don't understand what exactly would be ill-formed about this. So
Thanks, and now for following example (this is the issue I should has
posted first)
enum class mybyte : unsigned char{};
using T1 = mybyte;
auto buf = new T1 [100];
unsigned char * ptr = reinterpret_cast< unsigned char * > ( buf ) ;
*(ptr+10) = 50;
delete []buf;
so nowe we access enum objects via the unsigned char (pointer) that
happens to be the underlying type, but is that enough to avoid need for
memcpy?
Further question would be: for which T1 types you need to first memcpy
it?
> long as `T1` is a type which is default constructible and `T1` can be
> constructed from the integer literal 50, this code is fine. At no
> point are you reading any values as bytes. The fact that `unsigned
> char` is involved is essentially irrelevant.
>
> ptr is a pointer to an array of 100 `T1`s. So adding `10` to `ptr` is
> well-defined; it points to the 10th element (zero-based) of the array.
> `ptr + 10` is a valid pointer, and it is a pointer of that points to
> the type `T1`. It is also a pointer to an object of type `T1`. `T1` is
> the dynamic type of the object being pointed to, so [basic.lval/11.1]
> is satisfied.
>
> There is no "reading values as bytes" happening here.
Is there any particual reason why you are trying to avoid memcpy here?
While not guaranteed by the standard, pretty much any modern compiler is
going to produce the same code here whether you are going to use memcpy
or directly cast.
I've confirmed this on a project a few years ago, where we were trying
to enable strict-aliasing rules. So there should be no difference at
runtime between this:
int32_t readInt(char* data)
{
return *reinterpret_cast<int32_t*>(data);
}
and the standard-conformant way:
int32_t readInt(char* data)
{
int32_t out;
memcpy(&out, data, sizeof(int32_t));
}
Received on 2020-08-07 01:45:13