I have a C-array that looks like this:
char hexc[] = {
0x41, 0x80, 0x7a, 0x39, 0xea, 0x7e, 0x27, 0xfc,
0xe6, 0x45, 0x9c, 0x8b, 0xb5, 0xce, 0xa7, 0x35,
0x5f, 0xf2, 0x43, 0xcf, 0x89, 0xd8, 0x61, 0xec,
0xe7, 0xed, 0x2e, 0x34, 0x45, 0x0c, 0x32, 0xae,
0x71, 0x4f, 0x1c, 0xd8, 0xb5, 0x8c, 0x1e, 0xdd,
0x5d, 0x90, 0xf3, 0xf2, 0xe7, 0xa6, 0x4f, 0xef,
0xec, 0x96, 0xe3, 0xca, 0x8e, 0xeb, 0x64, 0x1d,
0x18, 0xa9, 0x95, 0xec, 0x64, 0x02, 0xf8, 0x26,
};
I knew that behind this hex-representations is a .GIF-file, what is the best way to generate from this hex-values a viewable file again? And how to add the missing GIF-header?
You would just open the file and write to it:
FILE *f = fopen("filename.gif", "wb");
if (!f) return; // or do something else
fwrite(hexc, 1, sizeof(hexc), f);
fclose(f);
Make sure to #include <stdio.h>.
open the file as binary
ofstream outfile ("new.gif",ofstream::binary);
and then write your buffer
outfile.write (hexc, sizeof hexc);
Turbo C DOS code
/****************************************************************************
** This support Compuserve 256 colour GIF87a and GIF89a image up to **
** 320x200 in size. **
****************************************************************************/
//This program requires a stack of at least 19.5K!!
#include "stdio.h"
typedef
struct GIFHeader {
char Signature [7];
unsigned int ScreenWidth, ScreenHeight;
unsigned char Depth, Background, Zero;
};
struct GIFDescriptor {
char Separator;
unsigned int ImageLeft, ImageTop, ImageWidth, ImageHeight;
unsigned char Depth;
};
char far *Screen = (char far *)0xA0000000L;
//For loading from the file
FILE *GIFFile;
unsigned int BPointer;
unsigned char Buffer [257];
//GIF data is stored in blocks of a certain size
unsigned char BlockSize;
//For loading the code
unsigned char CodeSize;
char BitsIn;
unsigned char Temp;
//Coordinates
unsigned int X, Y, tlX, tlY, brX, brY;
//The string table
unsigned int Prefix [4096];
unsigned char Suffix [4096];
//This sets the display to VGA 320x200 in 256 colours
void VGAScreen ()
{
asm {
mov ax, 0x13
int 0x10
}
}
//This resets the display to text mode
void TextScreen ()
{
asm {
mov ax, 0x3
int 0x10
}
}
//This sets a DAC register to a specific Red Green Blue-value
void SetDAC(unsigned char DAC, unsigned char R, unsigned char G, unsigned char B)
{
outportb (0x3C8, DAC);
outportb (0x3C9, R);
outportb (0x3C9, G);
outportb (0x3C9, B);
}
//This sets one pixel on the screen
void PutPixel (unsigned int x, unsigned int y, unsigned char c)
{
Screen [(y << 8) + (y << 6) + x] = c;
}
//Function to read from the buffer
unsigned char LoadByte ()
{
//Read next block}
if (BPointer == BlockSize) {
fread (Buffer, BlockSize + 1, 1, GIFFile);
BPointer = 0;
}
//Return byte
return Buffer [BPointer++];
}
//Procedure to read the next code from the file
unsigned int ReadCode ()
{
int Counter;
unsigned int Code;
Code = 0;
//Read the code, bit by bit
for (Counter = 0; Counter < CodeSize; Counter++) {
//Maybe, a new byte needs to be loaded with a further 8 bits
if (++BitsIn == 9) {
Temp = LoadByte ();
BitsIn = 1;
}
//Add the current bit to the code
if (Temp & 1) Code += 1 << Counter;
Temp >>= 1;
}
return Code;
}
//Procedure to draw a pixel
void NextPixel (unsigned int c)
{
//Actually draw the pixel on screen
PutPixel (X, Y, c & 255);
//Move to next row, if necessary
if (++X == brX) {
X = tlX;
Y++;
}
}
//Local function to output a string. Returns the first character.
unsigned char OutString (unsigned int CurCode)
{
unsigned int OutCount;
unsigned char OutCode [1024];
//If it's a single character, output that
if (CurCode < 256) {
NextPixel (CurCode);
} else {
OutCount = 0;
//Store the string, which ends up in reverse order
do {
OutCode [OutCount++] = Suffix [CurCode];
CurCode = Prefix [CurCode];
} while (CurCode > 255);
//Add the last character
OutCode [OutCount++] = CurCode;
//Output all the string, in the correct order
do {
NextPixel (OutCode [--OutCount]);
} while (OutCount);
}
//Return 1st character
return CurCode;
}
//This actually loads the GIF
void LoadGIF (char *Filename)
{
//For loading from the GIF file
struct GIFHeader Header;
struct GIFDescriptor Descriptor;
//Colour information
unsigned char BitsPerPixel,
NumOfColours;
unsigned int DAC;
unsigned char Palette [256][3];
//For indexing the string table
unsigned int FirstFree, FreeCode;
//All the code information
unsigned char InitCodeSize;
unsigned int Code, OldCode, MaxCode;
//Special codes
unsigned int ClearCode, EOICode;
//Check whether the GIF file exists, and open it
GIFFile = fopen (Filename, "rb");
if (GIFFile == 0) {
TextScreen ();
printf ("Could not open file %s", Filename);
return;
}
//Read header
fread (&Header, 6, 1, GIFFile);
Header.Signature [6] = 0;
fread (&Header.ScreenWidth, sizeof (Header) - 7, 1, GIFFile);
//Check signature and terminator
if ((strcmp (Header.Signature, "GIF87a")
&& strcmp (Header.Signature, "GIF89a"))
|| Header.Zero) {
TextScreen ();
printf ("Not a valid GIF file\n");
return;
}
//Get amount of colours in image
BitsPerPixel = 1 + (Header.Depth & 7);
NumOfColours = (1 << BitsPerPixel) - 1;
//Load global colour map
fread (Palette, 3, (NumOfColours + 1), GIFFile);
for (DAC = 0; DAC <= NumOfColours; DAC++)
SetDAC (DAC, Palette [DAC][0] >> 2,
Palette [DAC][1] >> 2,
Palette [DAC][2] >> 2);
//Load the image descriptor
fread (&Descriptor, sizeof (Descriptor), 1, GIFFile);
if (Descriptor.Separator != ',') {
TextScreen ();
printf ("Incorrect image descriptor.\n");
return;
}
//Get image corner coordinates
tlX = Descriptor.ImageLeft;
tlY = Descriptor.ImageTop;
brX = tlX + Descriptor.ImageWidth;
brY = tlY + Descriptor.ImageHeight;
//Some restrictions apply
if (Descriptor.Depth & 128) {
TextScreen ();
printf ("Local colour maps not supported\n");
return;
}
if (Descriptor.Depth & 64) {
TextScreen ();
printf ("Interlaced images not supported\n");
return;
}
//Get initial code size
fread (&CodeSize, 1, 1, GIFFile);
//GIF data is stored in blocks, so it's necessary to know the size
fread (&BlockSize, 1, 1, GIFFile);
//Start loader
BPointer = BlockSize;
//Special codes used in the GIF spec
ClearCode = 1 << CodeSize; //Code to reset
EOICode = ClearCode + 1; //End of file
//Initialize the string table
FirstFree = ClearCode + 2; //Strings start here
FreeCode = FirstFree; //Strings can be added here
//Initial size of the code and its maximum value
InitCodeSize = ++CodeSize;
MaxCode = 1 << CodeSize;
BitsIn = 8;
//Start at top left of image
X = Descriptor.ImageLeft;
Y = Descriptor.ImageTop;
do {
//Read next code
Code = ReadCode ();
//If it's an End-Of-Information code, stop processing
if (Code == EOICode) break;
//If it's a clear code...
else if (Code == ClearCode) {
//Clear the string table
FreeCode = FirstFree;
//Set the code size to initial values
CodeSize = InitCodeSize;
MaxCode = 1 << CodeSize;
//The next code may be read
Code = ReadCode ();
OldCode = Code;
//Set pixel
NextPixel (Code);
//Other codes
} else {
/*If the code is already in the string table, it's string is displayed,
and the old string followed by the new string's first character is
added to the string table.*/
if (Code < FreeCode)
Suffix [FreeCode] = OutString (Code);
else {
/*If it is not already in the string table, the old string followed by
the old string's first character is added to the string table and
displayed.*/
Suffix [FreeCode] = OutString (OldCode);
NextPixel (Suffix [FreeCode]);
}
//Finish adding to string table
Prefix [FreeCode++] = OldCode;
//If the code size needs to be adjusted, do so
if (FreeCode >= MaxCode && CodeSize < 12) {
CodeSize++;
MaxCode <<= 1;
}
//The current code is now old
OldCode = Code;
}
} while (Code != EOICode);
//Close the GIF file
fclose (GIFFile);
}
void main (int argcount, char *argvalue[])
{
char FileName [80];
//Check if a filename was passed as a parameter, otherwise ask for one
if (argcount > 1) {
strcpy (FileName, argvalue [1]);
} else {
printf ("Enter filename:");
gets (FileName);
}
//Switch to graphics screen
VGAScreen ();
//Load GIF file
LoadGIF (FileName);
//Wait for keypress
getch ();
//Switch back to text mode
TextScreen ();
}
Related
I want to search for a pattern of bytes that I receive in chunks (serially) as and when such data is available. For example, a pattern of bytes 0xbbffbbffbb. There is no guarantee that this pattern will be received in full, so doing a simple strnstrn may not be the solution. What algorithm can I use to look for this pattern? My approach is to look for the first byte (in this case 0xbb), then ensure I have 4 more bytes and then compare it with the string. Though it fails if there is some garbage data after two bytes, say 0xbbff01[bbffbbffbb].
My code(sorry if shabby) looks like this:
char* pattern_search(char* buff, size_t *bytes_read)
{
char* ptr = buff;
uint16_t remaining_length = *bytes_read;
while(1) {
// look for one byte in the stream
char* pattern_start = memmem((void*)ptr, remaining_length, 0xbb, 1);
if (pattern_start == NULL) {
// printf("nothing found\n");
return NULL;
}
int pos = pattern_start - ptr;
remaining_length = remaining_length - pos;
ptr = pattern_start;
// see if you have 5 bytes to compare, if not get more
remaining_length += get_additional_bytes();
// compare 5 bytes for pattern
pattern_start = memmem((void*)ptr, remaining_length, start_flag, PATTERN_LEN);
if (pattern_start == NULL) {
// move one step and continue search
ptr++;
remaining_length--;
// move these bytes back to beginning of the buffer
memcpy(buff, ptr, remaining_length);
ptr = buff;
*bytes_read = remaining_length;
if (remaining_length > 0) {
continue;
} else {
return NULL;
}
} else {
// found!
printf("pattern found!\n");
ptr = pattern_start;
break;
}
}
return ptr;
}
One can certainly find many different solutions here. One could be:
specify the pattern as an unsigned char array
calling of an 'input_received' function with received data blocks and a pointer to a callback function, which is called whenever the pattern is found
It could look like this:
#include <stdio.h>
static unsigned const char PATTERN[] = {0xbb, 0xff, 0xbb, 0xff, 0xbb};
static void found(size_t pos) {
printf("pattern found at index %zu\n", pos);
}
static void input_received(const unsigned char *const data,
int n,
void (*callback)(size_t)) {
static int match_count;
static size_t position;
for (int i = 0; i < n; i++, position++) {
if (data[i] == PATTERN[match_count]) {
match_count++;
} else {
match_count = data[i] == PATTERN[0] ? 1 : 0;
}
if (match_count == sizeof PATTERN) {
(*callback)(position - sizeof PATTERN + 1);
match_count = 0;
}
}
}
int main(void) {
unsigned char input[] = {0xff, 0x01, 0x02, 0xff, 0x00,
0xbb, 0xff, 0xbb, 0xff, 0xbb,
0xbb, 0xff, 0xbb, 0xff, 0xbb};
input_received(input, 2, found);
input_received(&input[2], 3, found);
input_received(&input[5], 2, found);
input_received(&input[7], 2, found);
input_received(&input[9], 5, found);
input_received(&input[14], 1, found);
return 0;
}
Test
This would then output the following in the debug console:
pattern found at index 5
pattern found at index 10
I'm capturing fingerprints using a device called Secugen Pro 20, it has its own SDK for Linux, and i want to capture the fingerprint image and save it as any image format.
They have this typedef unsigned char BYTE;
I declared my imageBuffer
BYTE *CurrentImageBuffer;
Then i allocate memory to it using the devices specs
CurrentImageBuffer = malloc(device_info.ImageWidth*device_info.ImageHeight);
And at some point at my code i capture image and pass CurrentImageBuffer as argument to the capture function:
SGFPM_GetImageEx(m_hFPM, CurrentImageBuffer, GET_IMAGE_TIMEOUT, NULL, GET_IMAGE_DESIRED_QUALITY)
Thats what the variable looks right after this line of code ( i can confirm that it captured a finger):
I just don't understand how to proceed creating an image from this buffer, as it doesn't look like a ByteArray
I don't even know if thats the right place to get my image from, but that looks like the right place because its a buffer, right?.
OBS: I'm new to C
This is a small sample program to write an 8-bit graylevel image into a Windows BMP file:
#include <stdio.h>
typedef unsigned char Byte;
int writeBMPGray8(FILE *f, int w, int h, const Byte *data)
{
unsigned bytesPerRow = (w + 3) & ~3; // align to 4 bytes (requirement)
unsigned size
= 14 // Bitmap file header size
+ 12 // DIB header size
+ 256 * 3; // palette size
unsigned gap = size;
size = (size + 3) & ~3; // align to 4 bytes (requirement)
gap = size - gap; // get size of gap between end of headers and raw data
unsigned offs = size; // store offset of raw data
size += h * bytesPerRow; // bitmap data size in file
/* write Bitmap file header (14 bytes) */
{ const Byte buffer[14] = {
'B', 'M', // magic code
size & 0xff, size >> 8 & 0xff, size >> 16 & 0xff, size >> 24 & 0xff, // size of BMP file in bytes
0, 0, // reserved
0, 0, // reserved
offs & 0xff, offs >> 8 & 0xff, offs >> 16 & 0xff, offs >> 24 & 0xff // starting offset of pixel data
};
if (fwrite(buffer, sizeof buffer, 1, f) != 1) return -1; // ERROR!
}
/* write DIB header (12 bytes) */
{ const Byte buffer[12] = {
12, 0, 0, 0, // size of this header
w & 0xff, w >> 8 & 0xff, // bitmap width in pixels
h & 0xff, h >> 8 & 0xff, // bitmap height in pixels
1, 0, // number of color planes, must be 1
8, 0 // number of bits per pixel
};
if (fwrite(buffer, sizeof buffer, 1, f) != 1) return -1; // ERROR!
}
/* write color palette (3 * 256 bytes) */
for (int i = 0; i < 256; ++i) { // make a gray level palette
Byte buffer[3] = { i, i, i };
if (fwrite(buffer, sizeof buffer, 1, f) != 1) return -1; // ERROR!
}
/* write gap (to align start address of raw data with 4 */
for (int i = 0; i < gap; ++i) {
if (fputc(0, f) < 0) return -1; // ERROR!
}
/* write raw data */
for (int y = 0; y < h; ++y) { // for all rows
int x = 0;
for (; x < w; ++x) { // for all columns
if (fputc(*data++, f) < 0) return -1; // ERROR!
}
// write row padding
for (; x < bytesPerRow; ++x) {
if (fputc(0, f) < 0) return -1; // ERROR!
}
}
/* done */
return 0;
}
int main()
{
/* a sample image 6 x 8, gray level */
enum { w = 6, h = 8 };
const Byte imgRaw[w * h] = {
0x00, 0x30, 0x60, 0x90, 0xc0, 0xf0,
0x02, 0x32, 0x62, 0x92, 0xc2, 0xf2,
0x04, 0x34, 0x64, 0x94, 0xc4, 0xf4,
0x06, 0x36, 0x66, 0x96, 0xc6, 0xf6,
0x08, 0x38, 0x68, 0x98, 0xc8, 0xf8,
0x0a, 0x3a, 0x6a, 0x9a, 0xca, 0xfa,
0x0c, 0x3c, 0x6c, 0x9c, 0xcc, 0xfc,
0x0e, 0x3e, 0x6e, 0x9e, 0xce, 0xfe
};
FILE *f = fopen("test.bmp", "wb");
if (!f) return 1; // ERROR!
if (writeBMPGray8(f, w, h, imgRaw)) return 1; // ERROR!
if (fclose(f)) return 1; // ERROR!
return 0; // success
}
The sample image provides some kind of gradients horizontally and vertically. I've chosen a width of 6 intentionally to check/show that row alignment is done properly.
The implementation is based on the description in Wikipedia BMP file format.
To keep it short, I encoded the simplest format – the ancient BITMAPCOREHEADER of Windows 2.0 and OS/2 1.x. (MS Paint can load this as well as the Windows 10 preview. I tested with GIMP which loaded as well without any complaints.)
This is how it looks in GIMP:
The easiest way to get an image is to make a NetPBM PGM image - see Wikipedia NetPBM page.
So, if your image is say 640 px wide by 480 px tall, you would get a buffer from your SDK with 307,200 bytes and you would write that to a file and check it has the correct length. Call that image.raw.
Now you just need a PGM header, and as your image is greyscale and binary, you need a P5 header.
So, in Terminal you can put a header on:
{ printf "P5\n640 480\n255\n" ; cat image.raw ; } > image.pgm
If you are unfamiliar with that syntax, you can get the same with:
printf "P5\n640 480\n255\n" > image.pgm
cat image.raw >> image.pgm
And you can view that image with feh, gimp, Photoshop etc.
If you want to make it into a BMP, or JPEG, or PNG, use ImageMagick which is installed on most Linux distros and is available for macOS and Windows:
magick image.pgm image.png
or
magick image.pgm image.jpg
If your version of ImageMagick is v6 or older, use convert in place of magick:
convert image.pgm image.png
If you have correctly captured the image in CurrentImageBuffer, you can write this as raw file using the code fragment below:
fp = fopen(rawFileName,"wb");
fwrite (CurrentImageBuffer, sizeof (BYTE) , device_info.ImageHeight*device_info.ImageWidth , fp);
fclose(fp);
As I have used the same environment, I am sending the above fragment from my working codebase. Actually, raw file is later converted to template which is later used for matching / identification and not directly used for viewing etc. Variable rawFileName stores the name of the file as char array (string) where this buffer is stored.
I notcied that memmem is not available in MSVC for Windows, so I tried to write something for it. I have the following code:
void *memmem(const void *haystack_start, size_t haystack_len, const void *needle_start, size_t needle_len)
{
const unsigned char *haystack = (const unsigned char *)haystack_start;
const unsigned char *needle = (const unsigned char *)needle_start;
const unsigned char *h = NULL;
const unsigned char *n = NULL;
size_t x = needle_len;
/* The first occurrence of the empty string is deemed to occur at
the beginning of the string. */
if (needle_len == 0) {
return (void *)haystack_start;
}
/* Sanity check, otherwise the loop might search through the whole
memory. */
if (haystack_len < needle_len) {
return NULL;
}
for (; *haystack && haystack_len--; haystack++) {
x = needle_len;
n = needle;
h = haystack;
if (haystack_len < needle_len)
break;
if ((*haystack != *needle) || (*haystack + needle_len != *needle + needle_len))
continue;
for (; x; h++, n++) {
x--;
if (*h != *n)
break;
if (x == 0)
return (void *)haystack;
}
}
return NULL;
}
But, I do not think it works correctly. If I try something like this:
static const char haystack[24] = {
0x4e, 0x65, 0x76, 0x65, 0x72, 0x20, 0x67, 0x6f,
0x6e, 0x6e, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65,
0x20, 0x79, 0x6f, 0x75, 0x20, 0x75, 0x70, 0x2c,
};
static const char needle[8] = {
0x20, 0x79, 0x6f, 0x75, 0x20, 0x75, 0x70, 0x2c
};
char *res = memmem(haystack, sizeof(haystack), needle, sizeof(needle));
printf("%s", res);
The result is null. Any ideas where the problem might be?
I think you are overcomplicating this.
void *memmem(const void *haystack, size_t haystack_len,
const void * const needle, const size_t needle_len)
{
if (haystack == NULL) return NULL; // or assert(haystack != NULL);
if (haystack_len == 0) return NULL;
if (needle == NULL) return NULL; // or assert(needle != NULL);
if (needle_len == 0) return NULL;
for (const char *h = haystack;
haystack_len >= needle_len;
++h, --haystack_len) {
if (!memcmp(h, needle, needle_len)) {
return h;
}
}
return NULL;
}
Until haystack_len is greater or equal to needle_len, you should memory compare needle with current position in haystack. If it's true, return haystack.
There is no need to explicitly cast a const void * pointer const unsigned char *haystack = (const unsigned char *)haystack_start; is just const unsigned char *haystack = haystack_start;
As said in comments by #molbdnilo (*haystack != *needle) || (*haystack + needle_len != *needle + needle_len)) is just the same think. It becomes obvious, once you use [] operator rather then *: haystack[0] != needle[0] || haystack[0] + needle_len != needle[0] + needle_len. Even if you meant ... != needle[needle_len] this is out-of-bound access of needle.
The for is just strange:
for (; *haystack && haystack_len--; haystack++) {
if (haystack_len < needle_len)
break;
Why not:
for (; *haystack && haystack_len < needle_len; haystack_len--, haystack++)
?
And the expression *haystack is just invalid, you are not checking null-terminated string like in case of strstr. haystack points to any bytes in memory and may have zero as values. The haystack_len keeps the length of haystack.
You can use memcmp to compare memory, no need to write that part yourself.
The accepted answer is pretty good, but there are easy optimizations that can be made. For example, windows does provide a memchr function, and it is probably written in assembly language and is much more efficient than manually looping one character at a time from C and calling memcmp at every character. I didn't perform any benchmarks, but almost certainly this is not ideal.
Here's a solution the makes use of this optimization. We do the primary search with memchr to find the first byte of the needle, then do a memcmp to check the rest. Since there are 256 possible values for a byte, on average this will reduce the number of calls to memcmp by a factor of 255.
void *os_memmem(const void *src,int srclen,const void *trg,int trglen)
{
unsigned char *csrc = (unsigned char *)src;
unsigned char *ctrg = (unsigned char *)trg;
unsigned char *tptr,*cptr;
int searchlen,ndx=0;
/* add some initial error checking if you want */
while (ndx<=srclen) {
cptr = &csrc[ndx];
if ((searchlen = srclen-ndx-trglen+1) <= 0) {
return NULL;
} /* if */
if ((tptr = memchr(cptr,*ctrg,searchlen)) == NULL) {
return NULL;
} /* if */
if (memcmp(tptr,ctrg,trglen) == 0) {
return tptr;
} /* if */
ndx += tptr-cptr+1;
} /* while */
return NULL;
}
The following statements are the same
char needle[] = "a test";
char needle[7] = { 'a', ' ', 't', 'e', 's', 't', '\0' };
Your haystack does not have a '\0' at the same place as needle.
Try with
// needle is NOT a string
char needle[6] = "a test"; // needle is NOT a string
for (; *haystack && haystack_len--; haystack++) {
Here you're decrementing haystack_len at the start of the loop. This means that when you reach your match haystack_len = 7 but needle_len = 8. Therefore you fail the f (haystack_len < needle_len) check and continue. As Kamil notes in the comments you probably don't want a nul check on haystack either. So I'd suggest
for (; haystack_len > 0; ++haystack, --haystack_len) {
Is it possible to initialise an array of uint8_t with a struct?
What I want to achieve is something similar to:
#define BIGGER_THAN_STRUCT 1024
struct Device {
uint32_t address;
uint32_t id;
};
const uint8_t bytes[BIGGER_THAN_STRUCT] = (struct Device) {
.address = 123,
.id = 456,
};
The reason I want to do this it to get an easy overlay view of the content I write to the byte array. I simply want an easy interface to whatever first bytes I need for the information that is displayed by the structure.
If thats not possible, what's the closest thing to it?
The standard way in C to overlay data types is by using unions:
#include <stdio.h>
#include <stdint.h>
#define BIGGER_THAN_STRUCT 1024
struct Device {
uint32_t address;
uint32_t id;
};
union Memory {
uint8_t bytes[BIGGER_THAN_STRUCT];
struct Device devices[BIGGER_THAN_STRUCT/sizeof(struct Device)];
};
const union Memory memory = {
.devices = {
{ .address = 123, .id = 30 },
{ .address = 111, .id = 89 }
}
};
int main(void)
{
unsigned i;
for (i = 0; i < 16; i++)
printf("%d ", memory.bytes[i]);
putchar('\n');
return 0;
}
,
$ ./a
123 0 0 0 30 0 0 0 111 0 0 0 89 0 0 0
Beside approaching this via a union (as proposed by hdante here https://stackoverflow.com/a/27462808/694576) instead of trying:
const uint8_t bytes[BIGGER_THAN_STRUCT] = (struct Device) {
.address = 123,
.id = 456,
};
do quick and dirty:
uint8_t bytes[BIGGER_THAN_STRUCT] = {0};
*((struct Device *) bytes) = ((struct Device) {
.address = 123,
.id = 456,
});
or better do:
struct Device dev = {
.address = 123,
.id = 456,
};
uint8_t bytes[BIGGER_THAN_STRUCT] = {0};
...
size_t size_dev = sizeof dev;
memcpy(bytes, &dev, size_dev);
Then inspect array bytes up to the size_dev - 1th element.
This will do it then
static const uint8_t buffer[BIGGER_THAN_STRUCT] = {
0x7b, 0x00, 0x00, 0x00,
0xc8, 0x01, 0x00, 0x00
};
I think you maybe want to do something like that, even if the copy is not that necessary as b_sample is exactly what you need.
#include <stdio.h>
#include <stdint.h>
typedef struct Device dev;
struct Device {
uint32_t address;
uint32_t id;
};
int main(void) {
//create an instance `sample.address=123` and `sample.id=456`
dev sample = (dev) { 123, 456 };
//convert dev pointer to byte pointer, so you loop through bytes
uint8_t* b_sample = (uint8_t *)(&sample);
//buffer for copy
uint8_t* bytes[1024];
int size = (int)(sizeof(dev)/sizeof(uint8_t)), i;
for(i = 0; i < size; i++) {
bytes[i] = b_sample[i];
//see what values you copy
printf("%x ", bytes[i]);
}
return 0;
}
Demo: http://codepad.org/wE8dbBV1
If you want to divide the struct into uint16_t segments you can safely replace all uint8_t with uint16_t
Usually, when I have to work with bag of structured bytes, I create a "view" struct/class that gives me some higher-level interface to a block of memory. Manual pointer arithmetic is usually too error prone to be repeated. Create a "memory view" structure and unit-test it properly.
struct memory_view {
uint32_t *addr;
uint32_t *id;
};
void view_init(struct memory_view *view, void *buf, size_t bufsz) {
// TODO: validate buffer size using bufsz here
view->addr = (uint32_t*)buf;
view->id = (uint32_t*)(buf + sizeof(uint32_t));
}
struct memory_view view;
uint8_t buffer[LARGE_NUMBER];
view_init(&view, buffer, LARGE_NUMBER);
*view->addr = 0xDEADBEEF;
*view->id = 0xCAFEBABE;
You can see a similar technique in device drivers, when structures are initialized to access different hardware registers located in some memory region.
You could also get a buffer pointer, cast it to structure and try using this memory block as it were a structure. Doable, but memory alignment can bite you hard. Such code may or may not work, depending on compiler and system architecture.
Does this:
#define BIGGER_THAN_STRUCT 1024
struct Device {
uint32_t address;
uint32_t id;
};
struct DeviceAndData {
struct Device d;
char filler[BIGGER_THAN_STRUCT - sizeof(Device)];
};
const struct DeviceAndData bytes_pre = { .d = { .address = 123, .id = 456 } };
const uint8_t* bytes = (uint8_t*)&bytes_pre;
do the trick? :)
There is an alternative to using a uint8_t byte[] array. You can also make use of a struct utilizing a bitfield for each addr and id. You (may/may not) find it more convenient, but it does provide an easy way to keep the offset information associated with any give addr/id pair.
I don't believe there is a way to directly make use of struct type Designated Initializers to fill the uint8_t byte array. I think the closest full initialization would be with memcpy. I've included that in the example below. Note, there is nothing that prevents you from filling the uint8_t byte array with memcpy, but then you have to track the offset within the uint8_t byte array to accurately point to any given byte in either addr or id for any given element. This is where the bitfield makes things a little easier. You get a one-to-one correlation between the struct Device index and the uibitfield index with a1..4 and b1..4 being the bytes within each addr and id, respectively.
A version using the uint8_t array is shown below this version.
Here is a short example with test data in an array of struct Device:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef struct /* bitfield corresponding to struct Device */
{
unsigned int a1 : 8,
a2 : 8,
a3 : 8,
a4 : 8;
unsigned int b1 : 8,
b2 : 8,
b3 : 8,
b4 : 8;
} uibitfield;
struct Device { /* original struct Device */
uint32_t addr;
uint32_t id;
};
int main () {
/* test data in an array of struct Device */
struct Device dev[] = { {0x4009f0, 0}, {0x4009f1, 1}, {0x4009f2, 2}, {0x4009f3, 3},
{0x4009f4, 4}, {0x4009f5, 5}, {0x4009f6, 6}, {0x4009f7, 7},
{0x4009f8, 8}, {0x4009f9, 9}, {0x4009fa, 10}, {0x4009fb, 11},
{0x4009fc, 12}, {0x4009fd, 13}, {0x4009fe, 14}, {0x4009ff, 15},
{0x400a00, 16}, {0x400a01, 17}, {0x400a02, 18}, {0x400a03, 19} };
int it = 0; /* general iterator */
size_t sz = sizeof (dev)/sizeof (*dev); /* size of array */
/* create validate and fill bitfield array */
uibitfield *bytes = calloc (sz, sizeof (*bytes));
if (!bytes) {
fprintf (stderr, "error: allocation failed.\n");
return 1;
}
memcpy (bytes, dev, sz * sizeof (dev));
/* print bytes in each addr & id in dev */
for (it = 0; it < sz; it++)
printf ("\n addr[%2d]: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n id[%2d]: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
it, (bytes + it)->a1, (bytes + it)->a2, (bytes + it)->a3, (bytes + it)->a4,
it, (bytes + it)->b1, (bytes + it)->b2, (bytes + it)->b3, (bytes + it)->b4);
printf ("\n");
return 0;
}
output:
$ ./bin/memview
addr[ 0]: 0xf0, 0x09, 0x40, 0x00
id[ 0]: 0x00, 0x00, 0x00, 0x00
addr[ 1]: 0xf1, 0x09, 0x40, 0x00
id[ 1]: 0x01, 0x00, 0x00, 0x00
addr[ 2]: 0xf2, 0x09, 0x40, 0x00
id[ 2]: 0x02, 0x00, 0x00, 0x00
addr[ 3]: 0xf3, 0x09, 0x40, 0x00
id[ 3]: 0x03, 0x00, 0x00, 0x00
addr[ 4]: 0xf4, 0x09, 0x40, 0x00
id[ 4]: 0x04, 0x00, 0x00, 0x00
(snip)
Note: it was a unclear how you would be using/filling struct Device and how much of an initial peek you wanted at the data in stuct Device, so this is just intended as an example of viewing the data.
using a uint8_t byte array:
If you do want to use the `uint8_t array, the changes needed are minimal:
/* using a uint8_t byte array */
uint8_t *bytearr = calloc (sz * 4, sizeof (*bytearr));
if (!bytearr) {
fprintf (stderr, "error: allocation failed.\n");
return 1;
}
memcpy (bytearr, dev, sz * sizeof (dev));
/* print bytes in each addr & id in dev using uint8_t array */
for (it = 0; it < sz * 4; it+=8)
printf ("\n addr[%2d]: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n id[%2d]: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
it, bytearr[it], bytearr[it+1], bytearr[it+2], bytearr[it+3],
it, bytearr[it+4], bytearr[it+5], bytearr[it+6], bytearr[it+7]);
output is the same
Executive summary:
How can I define an arbitrarily-sized 2D array in C?
How can I determine the dimensions of that array at compile-time?
Full disclosure:
I'm writing code for an embedded controller. My application requires several lookup tables with different sizes which will all be used by one lookup function (a binary search). Here is what I have so far:
typedef struct
{
unsigned char count; // number of rows in the table
unsigned char width; // number of bytes in each row
const unsigned char * data; // pointer to table data[count][width]
}
LookupTable;
// returns the index of a value from within a table
unsigned char Lookup(unsigned long value, const LookupTable * table);
This part is working. What I would like to do now is define these tables in my source without having to manually enter the count and width constants. Here is what I am doing now:
#define T1_count 100
#define T1_width 3
const unsigned char table1_data[T1_count][T1_width] =
{
{ 0x12, 0x34, 0x56 },
{ 0x12, 0x38, 0x12 },
...
};
const LookupTable table1 = { T1_count, T1_width, table1_data };
Here is what I would like to be able to do (pseudo-code, since this array definition will not actually compile):
const unsigned char table1_data[] =
{
{ 0x12, 0x34, 0x56 },
{ 0x12, 0x38, 0x12 },
...
};
const LookupTable table1 =
{
get_count_expr(table1_data),
get_width_expr(table1_data),
table1_data
};
Obviously, get_count_expr and get_width_expr would have to be constant expressions of some sort, based on the size of the table, and not actual function calls.
To be clear, no part of this design is cast in stone. I'm just posting what I have so far, in the hopes that my intent is clear. Any ideas for improvement would be appreciated.
The "why":
These tables will be changed often, and it would make maintenance easier if entries could be added and removed, or the width of a table changed without having to manually adjust the constants each time. Having to keep track of the sizes manually can be error-prone and violates DRY. I'm looking for a better way.
Hmmm ... you can leave the leftmost size to the compiler:
#define T1_WIDTH 3
const unsigned char table1_data[][T1_WIDTH] =
{
{ 0x12, 0x34, 0x56 },
{ 0x12, 0x38, 0x12 },
/* ... */
};
T1_count = sizeof table1_data / sizeof *table1_data;
T1_width = sizeof *table1_data;
Well, it's ugly as hell, but I think the only way to do it within the constraints you've listed is to include the data in a string, and than have initialization code parse the string and generate the table. Ideally you'd do that in a script rather than use C to do it, but if it has to be in C, it has to be in C..
Note that in no way do I claim the following to be production code, but it's just a proof of concept...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define datatable "\
{ 0x12, 0x34, 0x56 },\
{ 0x14, 0x36, 0x10 },\
{ 0x13, 0x37, 0x11 },\
{ 0x12, 0x38, 0x12 }"
typedef struct
{
unsigned char count; // number of rows in the table
unsigned char width; // number of bytes in each row
unsigned char **data; // pointer to table data[count][width]
}
LookupTable;
int parsedatatable(char *data, LookupTable **table) {
char *p, *sp, save;
unsigned char *tabledata;
int count = 0, width = 0;
unsigned int tmp;
int i,j;
/* find count */
p = strstr(data,"{");
while (p) {
p++;
p = strstr(p, "{");
count++;
}
/* find width */
p = strstr(data, "{");
p++;
sp = strstr(p, "}");
if (sp != NULL) {
save = *sp;
*sp = '\0';
}
while (p) {
p = strstr(p, ",");
width++;
if (p != NULL) p++;
}
if (sp != NULL) {
*sp = save;
}
printf("Count = %d, width = %d\n",count, width);
tabledata = (unsigned char *)malloc(width*count*sizeof(unsigned char));
*table = (LookupTable *)malloc(sizeof(LookupTable));
(*table)->data = (unsigned char **)malloc(count*sizeof(unsigned char*));
for (i=0; i<count; i++) {
(*table)->data[i] = &(tabledata[i*width]);
}
(*table)->count = count;
(*table)->width = width;
p = data;
for (i=0; i<count; i++) {
p = strstr(p,"{");
if (!p) {
fprintf(stderr,"Fail (a) reading in data!: %s\n",data);
free((*table)->data);
free(tabledata);
free(*table);
return -1;
}
p++;
for (j=0; j<width; j++) {
printf("Scanning <%s>, ",p);
sscanf(p,"%x",&tmp);
printf("got %d\n",tmp);
(*table)->data[i][j] = tmp;
p = strstr(p,",");
if (!p && j<width-1) {
fprintf(stderr,"Fail (b) reading in data!: %d, %d, %s\n",i,j,data);
free((*table)->data);
free(tabledata);
free(*table);
return -1;
}
p++;
}
}
return 0;
}
void printtable(LookupTable *table) {
unsigned char i,j;
for (i=0; i<table->count; i++) {
printf("{");
for (j=0; j<table->width; j++) {
printf("%x ",table->data[i][j]);
}
printf("}\n");
}
return;
}
int main(int argc, char **argv) {
char *data;
LookupTable *table;
data = (char *)malloc(strlen(datatable)+1);
strcpy(data,datatable);
parsedatatable(data,&table);
printtable(table);
return 0;
}
Well, but who fills these tables with data? I think that generated sources are better solution.
Define table1_data inside a header. You can auto-generate that header using a script. I do something similar to that for some of my projects. I have a CSV file with data and a Ruby or Python script that generates a header from it.