简体   繁体   中英

C contiguous data arrays

Say I have 2 arrays of data:

const uint8_t data1[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
const uint8_t data2[] = {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

I would like to be able to read these individually, but also as one contiguous block of data.

eg: I could access data1[8] in the same way as data[0].

Reason: I have various const data definitions in some individual.c files that I'd rather not touch (font bitmaps) but I'd like to append some extra data to them (extra special characters). So I'd like to

#include <original font file>
const uint8_t extrafonts[] = {<more font bitmaps>};

Can this be done?

The only way to guarantee contiguous allocation in C is to use arrays of arrays. In this case it would seem that a const uint8_t [2][8] would solve all your problems, so use that if possible.

Otherwise, more advanced solutions could use structs and unions. These guarantee an order of allocation but come with the disadvantage that the compiler can insert padding anywhere. In this specific case it wouldn't be a problem on any real-world computer, since chunks of 8 bytes are aligned. If you have a standard C compiler, you can do this:

#include <inttypes.h>
#include <stdio.h>

typedef union
{
  struct
  {
    uint8_t data1 [8];
    uint8_t data2 [8];
  };
  uint8_t data [16];
} data_t;

int main (void)
{
  const data_t data = 
  {
    .data1 = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07},
    .data2 = {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
  };
  
  for(size_t i=0; i<16; i++)
  {
    printf("%.2"PRIx8" ", data.data[i]);
  }
}

Now you can access the arrays individually through data.data1 / data.data2 or as one, with data.data .

In cases where you worry about struct padding, you'll have to add some non-standard #pragma pack(1) or similar compiler-specific instruction.

There is another alternative that might be applicable to your use case: Use external preprocessing.

Use your favorite scripting language with some regular expression magic to read original font source file, and append extra font data at the end of array. Then save it to new file and use that in compilation instead.

This might seem a lot of work at first, but c files which are generated by tools (which I assume is the case with your font bitmaps) tend to have predictable format that is not too hard to parse.

You could probably use:

struct ArrayPair
{
    uint8_t data1[8];
    uint8_t data2[8];
};

const struct ArrayPair data =
{ 
    { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 },
    { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }
};

Now you can probably get away with using:

data.data1[8]

It isn't very elegant. Your requirement is not sensible.

You said that these are 2 global arrays on different source files. So I am ignoring any options where you can group these with unions or structures.

Now the bad news: There is absolutely no guarantee that 2 global variables will end up next to each other in memory with standard C rules.

You can do this, but you need to use compiler specific extensions instead. You need to:

  • Use manual memory placement to place variables next to each other.

  • Disable any optimizations or other compiler features that might break your code because you are accessing array out of bounds.

Note that I am assuming that you are in system where resources are limited, for example, some embedded system. If that is not the case, then simply create third array, and merge 2 arrays at program startup.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM