unions

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

guys, is there away using unions to define a struct of varying sizes.

 

I want a struct that can be either 1byte, 2 byte, 3byte or 4 byte in size?

 

say for the 2 byte struct I would want:

 


union{
    unsigned char byte1;
    unsigned char byte2;
}

or a 4 byte struct:

union{
    unsigned char byte1;
    unsigned char byte2;
    unsigned char byte3;
    unsigned char byte4;
}

thi for the run length encoder I'm finishing.  It works with 3 bytes but I would like away of easily using it for say 16bit data without writing the function again.

Last Edited: Thu. Nov 21, 2019 - 12:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Frequently:
 

 struct foo {
   int header;
   int length;
   uint8_t data[1];
} *bar;

bar = malloc(sizeof(*bar) + strlen(mydata) - 1);
memcpy(bar->data, mydata, strlen(data));

 

Pretty unsafe, probably.  But you're already talking about fooling the typing system...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

with gcc you can even use data[0], IIRC, so you don't have to do the "-1" in you size calculation

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Flexible array members (added in C99) are what you want.

 

#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#define VICTOR_SIZE 3U

typedef struct {
    size_t size;
    int    data[];
} Vector;

int main( void )
{
    Vector * victor = malloc( sizeof( Vector ) + VICTOR_SIZE );
    assert( victor );

    victor->size = VICTOR_SIZE;
    victor->data[ 0 ] = 3;
    victor->data[ 1 ] = 2;
    victor->data[ 2 ] = 4;

    printf( "Flight 209'er clear for vector " );
    for ( size_t i = 0; i < victor->size; ++i ) {
        printf( "%d", victor->data[ i ] );
    } // for
    puts( "." );

    free( victor );
}

 

github.com/apcountryman/build-avr-gcc: a script for building avr-gcc

github.com/apcountryman/toolchain-avr-gcc: a CMake toolchain for cross compiling for the Atmel AVR family of microcontrollers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm just going to use bytes and use:

memcmp( , , bytes required t analysis)

 

offsetting: instead of struct24 pixel++ to do pixel += 3

 

and so on

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Typedef[*] each of your smaller sizes, then make a union of the result:

 

typedef small uint8_t;
typedef medium uint16_t;
typedef large uint32_t;

union {
    small;
    medium;
    large;
} tutti_frutti;

tutti_frutti tf;

tf.small = 3;
tf.medium = 4000;
tf.large = 500000;

Note that

(a) writing to any of the members *will* thump the other members; they share the same memory space

(b) extremely non-portable; packing will be different between different compilers and different architectures

(c) writing to one member and reading another but quite what is read is implementation dependent; don't even think about it.

 

Neil

 

[*] the typedef isn't strictly necessary in this example; you could drop the int types in directly. But if you had, for example, enums or structs as members than typedef makes it a bit cleaner.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

barnacle wrote:
(c) writing to one member and reading another but quite what is read is implementation dependent; don't even think about it.

Although doing this is very commonly seen, it is an abuse of the standard!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Um Neil. That is not going to work. For starters the format of a typedef if "typedef list_of_stuff_to_build_type new_typename" but you are using it in the sense "typedef new_typename list_of_stuff_to_build_type" but even if you correct that:

typedef uint8_t small;
typedef uint16_t medium;
typedef uint32_t large;

union {
	small;
	medium;
	large;
} tutti_frutti;

then:

D:\test\test\main.c(8,7): warning: declaration does not declare anything
		  small;
		       ^
D:\test\test\main.c(9,8): warning: declaration does not declare anything
		  medium;
		        ^
D:\test\test\main.c(10,7): warning: declaration does not declare anything
		  large;
		       ^
D:\test\test\main.c(7,1): warning: union has no members [-Wpedantic]
		 union {
		 ^
D:\test\test\main.c(13,1): error: unknown type name 'tutti_frutti'
		 tutti_frutti tf;
		 ^

that's because the union only contains type names, not members of those types. So correct that:

typedef uint8_t small_t;
typedef uint16_t medium_t;
typedef uint32_t large_t;

union {
	small_t small;
	medium_t medium;
	large_t large;
} tutti_frutti;

tutti_frutti tf;

int main(void) {
	tf.small = 3;
	tf.medium = 4000;
	tf.large = 500000;

and there's still problems because:

D:\test\test\main.c(13,1): error: unknown type name 'tutti_frutti'
		 tutti_frutti tf;
		 ^
		.././main.c: In function 'main':
D:\test\test\main.c(16,4): error: request for member 'small' in something not a structure or union
		  tf.small = 3;
		    ^
D:\test\test\main.c(17,4): error: request for member 'medium' in something not a structure or union
		  tf.medium = 4000;
		    ^
D:\test\test\main.c(18,4): error: request for member 'large' in something not a structure or union
		  tf.large = 500000;
		    ^

there's two way's to fix that one is to make the union a typedef so tutti_frutti is the typename and tf is the instantiation. The other (which I don't like so much) would be to make the union an instantiation. So this appears to work:

typedef uint8_t small_t;
typedef uint16_t medium_t;
typedef uint32_t large_t;

typedef union {
	small_t small;
	medium_t medium;
	large_t large;
} tutti_frutti;

tutti_frutti tf;

int main(void) {
	tf.small = 3;
	tf.medium = 4000;
	tf.large = 500000;
}

and so does this:

typedef uint8_t small_t;
typedef uint16_t medium_t;
typedef uint32_t large_t;

union {
	small_t small;
	medium_t medium;
	large_t large;
} tf;

int main(void) {
	tf.small = 3;
	tf.medium = 4000;
	tf.large = 500000;
}

But otherwise it looks fine! ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

3/10, shows promise, must try harder.

 

That's what I get for knocking something out while trying to debug an odd issue that only pops up only if the batteries are jiggled for exactly the right duration at exactly the right time... I really shouldn't type without testing :)

 

Neil