1

I have a large array of uint16_t.

Most of its members are uint16_t, but some are int16_t and some uint8_t.

How would you handle that?


By the way, I tried:

  1. Pointers:

    Used 2 pointers, one int16_t* and the other uint8_t*, both initialized to the start of the array, to access member of the array that are int16_t and uint8_t.

    (That worked initially, but I ran into problems when later in the program something else changed the value of the pointers, so I don't trust it.)

  2. Type definition with a union.

    In file.h:

    typedef union {
      uint16_t  u16[NO_OF_WORDS];     // As uint16_t
      int16_t   s16[NO_OF_WORDS];     // As int16_t
      uint8_t   u8[2 * NO_OF_WORDS];  // As uint8_t
    } ram_params_t;
    extern ram_params_t ram_params[];
    

    In file.c:

    ram_params_t ram_params[] = {0};
    

    (That really bombed.)

  3. Casting.

    (I didn't get very far with that.)

timrau
  • 22,578
  • 4
  • 51
  • 64
Davide Andrea
  • 1,357
  • 2
  • 15
  • 39
  • 1
    How do you know which elements are of which types? And can you show us the casting attempt? It seems the most sensible approach if they really have to be a single array. – Paul Roub Nov 14 '14 at 17:57
  • 1
    Why are you doing this? Why not just have a couple of variables of the other types? This seems very error-prone, and unmaintainable? – Degustaf Nov 14 '14 at 19:17
  • > Why are you doing this? -- because the Array (which is in an Embedded system) is shared with the outside world. The external system has access to that array and only to that array. And the data are of various types. – Davide Andrea Nov 14 '14 at 20:44
  • > How do you know which elements are of which types? -- By the index. I know that member at index 3 is an int16_t, and that member at index 5 is a pair of bytes. – Davide Andrea Nov 14 '14 at 20:45

2 Answers2

2

The problem with your attempt #2 was that you made an array of arrays.

Either do this:

typedef union {
  uint16_t  u16;     // As uint16_t
  int16_t   s16;     // As int16_t
  uint8_t   u8[2];   // As uint8_t
} ram_params_t;
extern ram_params_t ram_params[NO_OF_WORDS];

ram_params_t ram_params[NO_OF_WORDS];

uval16  = ram_params[i].u16;
sval16  = ram_params[i].s16;
uval8_1 = ram_params[i].u8[0];
uval8_2 = ram_params[i].u8[1];

Or you do this:

typedef union {
  uint16_t  u16[NO_OF_WORDS];     // As uint16_t
  int16_t   s16[NO_OF_WORDS];     // As int16_t
  uint8_t   u8[2 * NO_OF_WORDS];  // As uint8_t
} ram_params_t;
extern ram_params_t ram_params;

ram_params_t ram_params;

uval16  = ram_params.u16[i];
sval16  = ram_params.s16[i];
uval8_1 = ram_params.u8[2*i];
uval8_2 = ram_params.u8[2*i+1];

I don't see anything wrong with your attempt #1 either. I think that I would probably do that rather than using a union.

JS1
  • 4,745
  • 1
  • 14
  • 19
  • > I don't see anything wrong with your attempt #1 -- I didn't either until today, when the value in one of the pointers changed, corrupting the data in the array. The pointer gets set once at start-up. How can I be sure that it will still set correctly after a year of running without a reset? It's just not reliable. I would have to check it's value periodically, I guess. – Davide Andrea Nov 14 '14 at 21:02
  • 1
    Your pointer getting corrupted is a sign that something else in your program is wrong and is trashing memory. I would actually advise you to retry #1 and debug your program, otherwise you will probably end up with a different mysterious failure down the road. – JS1 Nov 14 '14 at 21:05
  • > Your pointer getting corrupted is a sign that something else in your program is wrong and is trashing memory. -- Yes, absolutely! I found it and fixed it. But that was a wake-up call on the danger of relying on the pointer. – Davide Andrea Nov 14 '14 at 21:05
  • "We should be careful to get out of an experience only the wisdom that is in it and stop there lest we be like the cat that sits down on a hot stove lid. She will never sit down on a hot stove lid again and that is well but also she will never sit down on a cold one anymore." - Mark Twain – JS1 Nov 14 '14 at 21:09
  • "Experience enables you to recognize a mistake when you make it again." Franklin P. Jones – Davide Andrea Nov 14 '14 at 21:45
  • I implemented you 1st suggestion. Not only does it work well, but making byte variables as a arrays of 2 items has really cleaned up my code. I love it! – Davide Andrea Nov 14 '14 at 21:54
  • @ JS1: Please see a followup to this question and your answer to it: http://stackoverflow.com/questions/26999975/array-doubles-in-size-if-a-struct-defines-both-its-uint16-t-words-and-uint8-t-by – Davide Andrea Nov 18 '14 at 17:14
  • 1
    @Davide Andrea: Interesting. The compiler I use doesn't behave that way. I guess you have to work around your compiler's strange behavior. – JS1 Nov 18 '14 at 20:05
1

The array elements of other types must be the same size as the uint16_t so just cast them. In the case of the 8-bit data, there is a possibility that the upper 8 bits are undefined, so I masked them off.

#include <stdio.h>

#define uint16_t    unsigned short
#define int16_t     short
#define uint8_t     unsigned char

int main() {
    uint16_t n;

    // convert uint16_t to int16_t
    n = 0xFFFF;
    printf ("%d\n", (int16_t)n);

    // convert uint16_t to uint8_t
    n = 168;
    printf ("%c\n", (uint8_t)(n & 0xFF));

    return 0;
}

Program output is

-1
¿
Weather Vane
  • 33,872
  • 7
  • 36
  • 56