Union in Union

New to FreeBASIC? Post your questions here.
Post Reply
Iczer
Posts: 99
Joined: Jul 04, 2017 18:09

Union in Union

Post by Iczer »

I wanted to make some kind of bit-state options variable, so I can access .STypeIs as 2bit element and STypeIs_Opt1, STypeIs_Opt2 as 1bit elements while they use same place in tagStateInfo Union. So it can be used like this:

Code: Select all

' ...........................................................................
Enum SType
	Is_Blank	= 0
	Is_Opt1
	Is_Opt2
	Is_ERR
	
End Enum
' ...........................................................................
Union tagStateInfo
	Dim As ULongInt Value
	Type
		Dim As ULongInt Is_New		: 1
		
		Dim As ULongInt Is_Base		: 1
		Dim As ULongInt Is_Complex	: 1
		Dim As ULongInt Is_Virtual	: 1
		
		Dim As ULongInt Is_ExtraOpt1	: 1
		Dim As ULongInt Is_ExtraOpt2	: 1
		Dim As ULongInt Is_ExtraOpt3	: 1
		Dim As ULongInt Is_ExtraOpt4	: 1
		Dim As ULongInt Is_ExtraOpt5	: 1
		
		
		Dim As ULongInt GroupIs_1		: 1
		Dim As ULongInt GroupIs_2		: 1
		Dim As ULongInt GroupIs_3		: 1
		
		Dim As ULongInt STypeIs			: 2 ....>|-> Dim As ULongInt STypeIs_Opt1	: 1
										                 |-> Dim As ULongInt STypeIs_Opt2	: 1
		
		Dim As ULongInt SID				: 11
		
		Dim As ULongInt IsNoOp3			: 7
		Dim As ULongInt IsNoOp4			: 8
		Dim As ULongInt IsNoOp5			: 8
		Dim As ULongInt IsNoOp6			: 8
		Dim As ULongInt IsNoOp7			: 8
	End Type
	
	Declare Operator Cast () Byref As ULongInt
	Declare Operator Let (Byref UintVal As ULongInt)
	Declare Operator Let (Byref tStateInfo As tagStateInfo)
End Union
' ...........................................................................
Operator tagStateInfo.Cast () Byref As ULongInt
  Return This.Value
End Operator
' ...........................................................................
Operator tagStateInfo.Let (Byref UintVal As ULongInt)
  This.Value = UintVal
End Operator
' ...........................................................................
Operator tagStateInfo.Let (Byref tStateInfo As tagStateInfo)
  This.Value = tStateInfo.Value
End Operator
' ...........................................................................

Dim As tagStateInfo MainState

MainState.Value = 0

MainState.STypeIs = Is_Opt1

Print "STypeIs_Opt1 = ";MainState.STypeIs_Opt1	' <-- expected "1"
Print "STypeIs_Opt2 = ";MainState.STypeIs_Opt2	' <-- expected "0"

MainState.STypeIs = Is_Opt2

Print "STypeIs_Opt1 = ";MainState.STypeIs_Opt1	' <-- expected "0"
Print "STypeIs_Opt2 = ";MainState.STypeIs_Opt2	' <-- expected "1"
fxm
Moderator
Posts: 12106
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union in Union

Post by fxm »

A Type or Union can also contain nested types or unions, allowing data members to be grouped as desired.
Type and Union can be directly nested on condition of alternating their nesting.
Only the main structure (Type or Union) can be named, the others (nested) must be unnamed.
Nested unnamed Type or Union can not have procedure members or static data members (same restriction for local scope named Type/Union).

Code: Select all

' ...........................................................................
Enum SType
   Is_Blank   = 0
   Is_Opt1
   Is_Opt2
   Is_ERR
   
End Enum
' ...........................................................................
Union tagStateInfo
   Dim As ULongInt Value
   Type
      Dim As ULongInt Is_New      : 1
      
      Dim As ULongInt Is_Base      : 1
      Dim As ULongInt Is_Complex   : 1
      Dim As ULongInt Is_Virtual   : 1
      
      Dim As ULongInt Is_ExtraOpt1   : 1
      Dim As ULongInt Is_ExtraOpt2   : 1
      Dim As ULongInt Is_ExtraOpt3   : 1
      Dim As ULongInt Is_ExtraOpt4   : 1
      Dim As ULongInt Is_ExtraOpt5   : 1
      
      
      Dim As ULongInt GroupIs_1      : 1
      Dim As ULongInt GroupIs_2      : 1
      Dim As ULongInt GroupIs_3      : 1
      Union
         Dim As ULongInt STypeIs        : 2
         Type
            Dim As ULongInt STypeIs_Opt1   : 1
            Dim As ULongInt STypeIs_Opt2   : 1
         End Type
      End Union
      Dim As ULongInt SID            : 11
      
      Dim As ULongInt IsNoOp3         : 7
      Dim As ULongInt IsNoOp4         : 8
      Dim As ULongInt IsNoOp5         : 8
      Dim As ULongInt IsNoOp6         : 8
      Dim As ULongInt IsNoOp7         : 8
   End Type
   
   Declare Operator Cast () Byref As ULongInt
   Declare Operator Let (Byref UintVal As ULongInt)
   Declare Operator Let (Byref tStateInfo As tagStateInfo)
End Union
' ...........................................................................
Operator tagStateInfo.Cast () Byref As ULongInt
  Return This.Value
End Operator
' ...........................................................................
Operator tagStateInfo.Let (Byref UintVal As ULongInt)
  This.Value = UintVal
End Operator
' ...........................................................................
Operator tagStateInfo.Let (Byref tStateInfo As tagStateInfo)
  This.Value = tStateInfo.Value
End Operator
' ...........................................................................

Dim As tagStateInfo MainState

MainState.Value = 0

MainState.STypeIs = Is_Opt1

Print "STypeIs_Opt1 = ";MainState.STypeIs_Opt1   ' <-- expected "1"
Print "STypeIs_Opt2 = ";MainState.STypeIs_Opt2   ' <-- expected "0"

MainState.STypeIs = Is_Opt2

Print "STypeIs_Opt1 = ";MainState.STypeIs_Opt1   ' <-- expected "0"
Print "STypeIs_Opt2 = ";MainState.STypeIs_Opt2   ' <-- expected "1"
fxm
Moderator
Posts: 12106
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union in Union

Post by fxm »

Note for UDT:
The default-constructor, the copy-constructor, the copy-assignment operator, and the destructor are automatically built by the compiler if they are needed and not explicitly defined by the user.
The implicit copy-assignment operator is already a shallow copy from field to field, so to define your own 'Operator Let (Byref tStateInfo As tagStateInfo)' to overwrite the implicit is useless as it does the same thing.
Iczer
Posts: 99
Joined: Jul 04, 2017 18:09

Re: Union in Union

Post by Iczer »

Thanks! This working but... there a problem or bug or I just not understand how it's should work. I mean - setting main value would not affect/clear any of bits placed after embedded union:

Code: Select all

Union tagStateInfo
	Dim As ULongInt Value
	Type
		Dim As ULongInt Is_Opt_01			: 1
		
		Dim As ULongInt Is_Opt_02  		: 1
		Dim As ULongInt Is_Opt_03			: 1
		Dim As ULongInt Is_Opt_04			: 1
		
		Dim As ULongInt Is_Opt_05			: 1
		Dim As ULongInt Is_Opt_06			: 1
		Dim As ULongInt Is_Opt_07			: 1
		Dim As ULongInt Is_Opt_08			: 1
		Dim As ULongInt Is_Opt_09			: 1
		Dim As ULongInt Is_Opt_10			: 1
		Dim As ULongInt Is_Opt_11			: 1
		
		Dim As ULongInt Is_Opt_12 			: 1
		Dim As ULongInt Is_Opt_13			: 1
		Dim As ULongInt Is_Opt_14			: 1
		
      Union
         Dim As ULongInt Is_Opt_15_16	: 2
         Type
            Dim As ULongInt Is_Opt_15	: 1
            Dim As ULongInt Is_Opt_16	: 1
         End Type
      End Union
      
		Dim As ULongInt Is_Opt_17_27		: 11
		
		Dim As ULongInt Is_Opt_28			: 1
		
		Dim As ULongInt IsNoOpt_29			: 1
		Dim As ULongInt IsNoOpt_30			: 1
		Dim As ULongInt IsNoOpt_31			: 1
		Dim As ULongInt IsNoOpt_32			: 1
		Dim As ULongInt IsNoOpt_3340		: 8
		Dim As ULongInt IsNoOpt_4148		: 8
		Dim As ULongInt IsNoOpt_4956		: 8
		Dim As ULongInt IsNoOpt_5764		: 8
	End Type
	
End Union
	
	
	Dim Status As tagStateInfo
	
	Status.Value = 0ULL
	
	Print "Status.Value = 0ULL"
	Print "Value = ";Bin(Status.Value,64)
	Print "Is_Opt_17_27 = ";Status.Is_Opt_17_27
	Print "-----------------------------------------------"
	
	Status.Is_Opt_17_27 = 2047
	
	Print "Status.Is_Opt_17_27 = 2047"
	Print "Value = ";Bin(Status.Value,64)
	Print "Is_Opt_17_27 = ";Status.Is_Opt_17_27
	
	Print "SizeOf = ";SizeOf(Status)
	Print "Len = ";Len(Status)
	Print "-----------------------------------------------"
	
	Dim StatusCopy As tagStateInfo
	
	StatusCopy = Status
	
	Print "StatusCopy = Status"
	Print "Value = ";Bin(StatusCopy.Value,64)
	Print "Is_Opt_17_27 = ";StatusCopy.Is_Opt_17_27
	Print "-----------------------------------------------"
	
	
	StatusCopy.Value = Status.Value
	
	Print "StatusCopy.Value = Status.Value"
	Print "Value = ";Bin(StatusCopy.Value,64)
	Print "Is_Opt_17_27 = ";StatusCopy.Is_Opt_17_27
	Print "-----------------------------------------------"
	
	StatusCopy.Value = 0
	
	Print "StatusCopy.Value = 0"
	Print "Value = ";Bin(StatusCopy.Value,64)
	Print "Is_Opt_17_27 = ";StatusCopy.Is_Opt_17_27
	Print "-----------------------------------------------"
	
	StatusCopy.Value = 0ULL
	
	Print "StatusCopy.Value = 0ULL"
	Print "Value = ";Bin(StatusCopy.Value,64)
	Print "Is_Opt_17_27 = ";StatusCopy.Is_Opt_17_27
	Print "-----------------------------------------------"
	
	StatusCopy.Value = &B0000000000000000000000000000000000000000000000000000000000000000
	
	Print "StatusCopy.Value = &B0000000000000000000000000000000000000000000000000000000000000000"
	Print "Value = ";Bin(StatusCopy.Value,64)
	Print "Is_Opt_17_27 = ";StatusCopy.Is_Opt_17_27
	Print "-----------------------------------------------"
	
	StatusCopy.Value = &B1111111111111111111111111111111111111111111111111111111111111111
	
	Print "StatusCopy.Value = &B1111111111111111111111111111111111111111111111111111111111111111"
	Print "***** = ";StatusCopy.Value
	Print "Value = ";Bin(StatusCopy.Value,64)
	Print "Is_Opt_17_27 = ";StatusCopy.Is_Opt_17_27
	Print "-----------------------------------------------"
	
	StatusCopy.Is_Opt_17_27 = 0
	
	Print "StatusCopy.Is_Opt_17_27 = 0"
	Print "Value = ";Bin(StatusCopy.Value,64)
	Print "Is_Opt_17_27 = ";StatusCopy.Is_Opt_17_27
	Print "-----------------------------------------------"
gives result's I don't understand:

Code: Select all

Status.Value = 0ULL
Value = 0000000000000000000000000000000000000000000000000000000000000000
Is_Opt_17_27 = 0
-----------------------------------------------
Status.Is_Opt_17_27 = 2047
Value = 0000000000000000000000000000000000000000000000000000000000000000
Is_Opt_17_27 = 2047
SizeOf =  24
Len =  24
-----------------------------------------------
StatusCopy = Status
Value = 0000000000000000000000000000000000000000000000000000000000000000
Is_Opt_17_27 = 2047
-----------------------------------------------
StatusCopy.Value = Status.Value
Value = 0000000000000000000000000000000000000000000000000000000000000000
Is_Opt_17_27 = 2047
-----------------------------------------------
StatusCopy.Value = 0
Value = 0000000000000000000000000000000000000000000000000000000000000000
Is_Opt_17_27 = 2047
-----------------------------------------------
StatusCopy.Value = 0ULL
Value = 0000000000000000000000000000000000000000000000000000000000000000
Is_Opt_17_27 = 2047
-----------------------------------------------
StatusCopy.Value = &B0000000000000000000000000000000000000000000000000000000000000000
Value = 0000000000000000000000000000000000000000000000000000000000000000
Is_Opt_17_27 = 2047
-----------------------------------------------
StatusCopy.Value = &B1111111111111111111111111111111111111111111111111111111111111111
***** = 18446744073709551615
Value = 1111111111111111111111111111111111111111111111111111111111111111
Is_Opt_17_27 = 2047
-----------------------------------------------
StatusCopy.Is_Opt_17_27 = 0
Value = 1111111111111111111111111111111111111111111111111111111111111111
Is_Opt_17_27 = 0
-----------------------------------------------
fxm
Moderator
Posts: 12106
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union in Union

Post by fxm »

It can't work the way you want it to.
A nested Union inserts another ULongInt in the structure, i.e. so 3 ULongInt in all.

Simpler example:

Code: Select all

Union test1
    Dim As Integer I
    Type
        Dim As Integer I1   : 1
        Dim As Integer I2_3 : 2
        Dim As Integer I4   : 1
    End Type
End Union
Print Sizeof(test1)

Union test2
    Dim As Integer I
    Type
        Dim As Integer I1         : 1
        Union
            Dim As Integer I2_3   : 2
            Type
                Dim As Integer I2 : 1
                Dim As Integer I3 : 1
            End Type
        End Union
        Dim As Integer I4         : 1
    End Type
End Union
Print Sizeof(test2)
fxm
Moderator
Posts: 12106
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union in Union

Post by fxm »

@Jeff,

Do you see a variant of the above 'test2' structure to fit on a single Integer (and not 3) ?
coderJeff
Site Admin
Posts: 4323
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Union in Union

Post by coderJeff »

As you have probably already noticed:
- bit field members in a TYPE are packed together, unless the next member is a non-bit field; a nested UNION is considered a non bit field.
- UNION fields must all start at the same address, including any nested TYPE.

Here's the variant I see:

Code: Select all

Union test3
    Dim As Integer I
    Type
        Dim As Integer I1   : 1
        Dim As Integer I2   : 1
        Dim As Integer I3   : 1
        Dim As Integer I4   : 1
    End Type
    Type
        Dim As Integer padbit_1  : 1
        Dim As Integer I2_3      : 2
    End Type
End Union
Print "Sizeof(test3) = " & Sizeof(test3)

dim as test3 a, b, c, d, e

a.I1   = 1 : print "I1"  , bin( a.I, 8 )
b.I2   = 1 : print "I2"  , bin( b.I, 8 )
c.I3   = 1 : print "I3"  , bin( c.I, 8 )
d.I4   = 1 : print "I4"  , bin( d.I, 8 )
e.I2_3 = 3 : print "I2_3", bin( e.I, 8 )
fxm
Moderator
Posts: 12106
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union in Union

Post by fxm »

@Jeff,
Thanks a lot.

@Iczer,
So, a solution to your problem might be as follows:

Code: Select all

Union tagStateInfo
   Dim As ULongInt Value
   Type
      Dim As ULongInt Is_Opt_01         : 1
     
      Dim As ULongInt Is_Opt_02         : 1
      Dim As ULongInt Is_Opt_03         : 1
      Dim As ULongInt Is_Opt_04         : 1
     
      Dim As ULongInt Is_Opt_05         : 1
      Dim As ULongInt Is_Opt_06         : 1
      Dim As ULongInt Is_Opt_07         : 1
      Dim As ULongInt Is_Opt_08         : 1
      Dim As ULongInt Is_Opt_09         : 1
      Dim As ULongInt Is_Opt_10         : 1
      Dim As ULongInt Is_Opt_11         : 1
     
      Dim As ULongInt Is_Opt_12         : 1
      Dim As ULongInt Is_Opt_13         : 1
      Dim As ULongInt Is_Opt_14         : 1
     
      Dim As ULongInt Is_Opt_15_16      : 2
     
      Dim As ULongInt Is_Opt_17_27      : 11
     
      Dim As ULongInt Is_Opt_28         : 1
     
      Dim As ULongInt Is_NoOpt_29       : 1
      Dim As ULongInt Is_NoOpt_30       : 1
      Dim As ULongInt Is_NoOpt_31       : 1
      Dim As ULongInt Is_NoOpt_32       : 1
      Dim As ULongInt Is_NoOpt_33_40    : 8
      Dim As ULongInt Is_NoOpt_41_48    : 8
      Dim As ULongInt Is_NoOpt_49_56    : 8
      Dim As ULongInt Is_NoOpt_57_64    : 8
   End Type
   Type
      Dim As ULongInt padbit_1_14       : 14  '' just used for padding
      Dim As ULongInt Is_Opt_15         : 1
      Dim As ULongInt Is_Opt_16         : 1
   End Type
End Union
Post Reply