public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* bit-fields integral promotion issues
@ 2021-04-12  2:46 He Leon
  2021-04-12  4:07 ` Liu Hao
  2021-04-12  5:22 ` Xi Ruoyao
  0 siblings, 2 replies; 3+ messages in thread
From: He Leon @ 2021-04-12  2:46 UTC (permalink / raw)
  To: gcc-help

Hi all,

I meet an issue of integral promotion. I have small APP as appended.

The bit-fields integral promotion(***shift = fl_a.e << 28***) result is different between Linux and windows.
a) Linux gcc:  fl_a.e is promoted as integer, and shift result is "0xffffffffe0000000",
b) windows: fl_a.e is promoted as unsigned integer, and shift result is "0x7e0000000"

Per C++ spec, seems Linux behavior is correct.

chapter 4.6, Working Draft, Standard for Programming Language C++
"A prvalue for an integral bit-field (9.6) can be converted to a prvalue of type int if int can represent all the values of the bit-field; otherwise, it can be converted to unsigned int if unsigned int can represent all the values of the bit-field. If the bit-field is larger yet, no integral promotion applies to it. If the bit-field has an enumerated type, it is treated as any other value of that type for promotion purposes."

1) can you confirm window's behavior is not right?
2) Is there any way to make the behaviors are the same over Linux and Window without change code?
     Since we have so much such coding in our project.
     It'll be much better if there is a building option to handle this.

Thanks a lot.
Leon

===================================================================


#include <stdio.h>

typedef union
{
   struct {
      unsigned long long m : 28;
      unsigned long long e : 8;
      unsigned long long s : 1;
   };
   unsigned long long hex : 37;
} fl;

int main()
{
   unsigned long long shift = 0;
   unsigned long long cast_shift = 0;
   fl fl_a;

   fl_a.m = 0;
   fl_a.e = 0x7e;
   fl_a.s = 0;

   shift = fl_a.e << 28;
   cast_shift = ((unsigned long long)fl_a.e) << 28;

   printf("%s() (a<<28)-0x%llx, ((uint64)a<<28)-0x%llx\n", __func__, shift, cast_shift);

   return 0;
}


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: bit-fields integral promotion issues
  2021-04-12  2:46 bit-fields integral promotion issues He Leon
@ 2021-04-12  4:07 ` Liu Hao
  2021-04-12  5:22 ` Xi Ruoyao
  1 sibling, 0 replies; 3+ messages in thread
From: Liu Hao @ 2021-04-12  4:07 UTC (permalink / raw)
  To: He Leon, gcc-help


[-- Attachment #1.1: Type: text/plain, Size: 962 bytes --]

在 2021/4/12 上午10:46, He Leon via Gcc-help 写道:
> I meet an issue of integral promotion. I have small APP as appended.
> 
> The bit-fields integral promotion(***shift = fl_a.e << 28***) result is different between Linux and windows.
> a) Linux gcc:  fl_a.e is promoted as integer, and shift result is "0xffffffffe0000000",
> b) windows: fl_a.e is promoted as unsigned integer, and shift result is "0x7e0000000"
> 
> Per C++ spec, seems Linux behavior is correct.

It is not Windows that is incorrect; it is MSVC that is incorrect, because if you compile this piece 
of code with mingw-w64 GCC, you will get the correct result.

Not only is there no option to change this behavior, your code also results in an overflow (because 
`fl_a.e` has type `int` which comprises 32 bits) which is undefined behavior.

`-Wsign-conversion` may help you catch such issues, but you probably have to change your code.


-- 
Best regards,
Liu Hao


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: bit-fields integral promotion issues
  2021-04-12  2:46 bit-fields integral promotion issues He Leon
  2021-04-12  4:07 ` Liu Hao
@ 2021-04-12  5:22 ` Xi Ruoyao
  1 sibling, 0 replies; 3+ messages in thread
From: Xi Ruoyao @ 2021-04-12  5:22 UTC (permalink / raw)
  To: gcc-help, He Leon

On 2021-04-12 02:46 +0000, He Leon via Gcc-help wrote:
> Hi all,
> 
> I meet an issue of integral promotion. I have small APP as appended.
> 
> The bit-fields integral promotion(***shift = fl_a.e << 28***) result is
> different between Linux and windows.
> a) Linux gcc:  fl_a.e is promoted as integer, and shift result is
> "0xffffffffe0000000",

/* snip */

> #include <stdio.h>
> 
> typedef union
> {
>    struct {
>       unsigned long long m : 28;
>       unsigned long long e : 8;
>       unsigned long long s : 1;
>    };
>    unsigned long long hex : 37;
> } fl;
> 
> int main()
> {
>    unsigned long long shift = 0;
>    unsigned long long cast_shift = 0;
>    fl fl_a;
> 
>    fl_a.m = 0;
>    fl_a.e = 0x7e;
>    fl_a.s = 0;
> 
>    shift = fl_a.e << 28;

You are invoking undefined behavior here. -fsanitize=undefined reports:

t.cc:23:19: runtime error: left shift of 126 by 28 places cannot be represented
in type 'int'

As the compiler can do "anything" for UB, there is no way to say who is correct
or who is wrong.

>    cast_shift = ((unsigned long long)fl_a.e) << 28;
> 
>    printf("%s() (a<<28)-0x%llx, ((uint64)a<<28)-0x%llx\n", __func__, shift,
> cast_shift);
> 
>    return 0;
> }
> 

-- 
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-04-12  5:23 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-12  2:46 bit-fields integral promotion issues He Leon
2021-04-12  4:07 ` Liu Hao
2021-04-12  5:22 ` Xi Ruoyao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).