I am trying to understand the process by which I can serialize and de-serialize data in C. I wrote code that I believe should write a simple struct to a char buffer.
#include <packet.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
typedef struct
{
int A;
int B;
int C;
}test_packet;
int main(int argc, char** argv)
{
test_packet p;
p.A = 1;
p.B = 2;
p.C = 3;
char buffer [sizeof(p)];
memcpy(buffer, &p, sizeof(p));
printf("%x \n", buffer);
return 0;
}
However, when I run this code, since the struct being serialized is statically coded, I expect to see a buffer that's the same each time. I don't, I see a buffer that appears to be full of random data:
./SerializePacket
41bf5380
./SerializePacket
d89fc790
./SerializePacket
aea2c00
./SerializePacket
d355dc10
Can anyone alleviate me of my ignorance here?
What you are printing is a pointer, the address of the buffer.
About serialization: you are copying the struct over the buffer, with padding and all. That it's not portable, unless you serialize and de-serialize in the same computer. To serialize a struct directly copying to the buffer, you should use packed structures (see: What is a "packed" structure in C?, https://en.wikipedia.org/wiki/Data_structure_alignment). Also, using an integer of fixed size is preferred for serialized data, for example, uint16_t for a 16 bits unsigned integer.
Related
I am working with a bunch of strings for logging. I want to refactor my code and make a new struct that combines the char, its length and allocated size. The idea is to make my internal string operations smoother and the code nicer to read, whilst assigning each string its own max allocated memory to keep the usage to a minimum but prevent stack overflow. I made this simple example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *str;
int size;
int max;
} Text;
void defText(Text *text, int max)
{
text->str=(char*) malloc(max * sizeof(char));
text->str="";
text->max=max;
}
int main() {
Text *a;
defText(a,50);
a->str="Test all you want";
printf("OUT: %s %zu %lu",a->str,strlen(a->str),sizeof(a->str));
return 0;
}
The function defText initializes and allocates memory. However, when I check the sizeof the char in my struct, I always get 8, no matter what I set in defText. Is this kind of struct handling strings and their properties together even possible? If so, what is wrong here?
There are several problems in your code, this is an example that cleans up these problems:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *str;
// you could use size to keep track of the strlen. That's particularly
// desirable if you find yourself calling strlen "a lot", since that
// function recalculates the length every time it's called
int size;
int max;
} Text;
void defText(Text *text, int max)
{
// no need to cast the return of malloc. In fact, sizeof(char) is defined by
// the standard to be 1 so you could take that out also.
text->str=malloc(max * sizeof(char));
// `=` is not the proper way to write strings in C, you must use strcpy
// or something similar. It looks like here you're simply trying to
// create an empty string.
//text->str="";
// per #JohnBollinger's comment, the best thing to do here to create
// an empty string is simply set to the first byte to the NUL
// terminator.
text->str[0] = '\0';
text->max=max;
}
int main() {
Text a; // store this in automatic memory, now the object exists without having to malloc
defText(&a,50); // Use & to pass the address of a to defText
// as mentioned, this is not the proper way to write data to a string in
// C. What you've done here is create a memory leak and point a.str to
// the string literal "Test all you want". Use strcpy (or similar) to
// write that string into the data you actually malloc'ed (using the dot
// operator now since `a` is no longer a pointer)
//a->str="Test all you want";
strcpy(a.str, "Test all you want");
// a.str is a pointer, and will always be 8 bytes on your system no matter
// the size of the memory it points to
printf("OUT: %s %zu %zu",a.str,strlen(a.str),sizeof(a.str));
// clean up allocated memory. Since we're about to exit, there's
// really no need to do this here (the OS will reclaim all allocated
// memory when the process ends), but if you're writing a more
// involved, long-running program, you need to be sure to handle
// memory allocations and deallocations appropriately as needed
free(a.str);
return 0;
}
Demo
The
a->str
is pointer .
the correct answer is
sizeof(*(a->str))
I am trying to modify a field inside a struct. I have no trouble doing this with other types (i.e. int, float etc.) but char * is giving me problems. I think I have to do something like:
typedef struct{
char *string_field;
} struct_name;
struct_name *struct_name1;
struct_name1 = (struct_name *) malloc(sizeof(struct_name));
strcpy(struct_name1->string_field, new_string);
printf("New string: %s\n", struct_name1->string_field);
But this gives me a segmentation fault. What reason do you think I would get this problem for? Initially, I thought maybe the char *string_field was not big enough to copy to, but I changed the size of it manually to be of size 100 (more than enough) and I still get this problem.
You reserve memory for your struct, which comprises a pointer to a string, but not the space for a string's content. Reserve memory for the string content and let your struct's pointer point to it; then you can copy newstring's content into that memory:
struct_name1->string_field = malloc(strlen(new_string)+1);
strcpy(struct_name1->string_field, new_string);
Allocate memory for the structure as well as for the string.
In example below there is a room for 63 characters in the string.
Remember to free the allocated memory.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char *string_field;
} struct_name;
int main()
{
struct_name *struct_name1;
struct_name1 = malloc(sizeof(struct_name));
struct_name1->string_field = malloc(64*sizeof(char));
strcpy(struct_name1->string_field, "new_string");
printf("New string: %s\n", struct_name1->string_field);
free(struct_name1->string_field);
free(struct_name1);
return 0;
}
OUTPUT:
New string: new_string
I have a binary file which contains 3 differents structs and a christmas text. On the first line of the binaryfile have they provided me with a int which represents the size of a package inside the file. A package contains 3 structs ,the chistmastext and the size.
The structs lies in a file called framehdr.h and the binary file I'm reading is called TCPdump.
Now am I trying to create a program att will read each package at a time and then withdraw the text.
I have started with something like this:
#pragma warning(disable: 4996)
#include <stdio.h>
#include <stdlib.h>
#include "framehdr.h"
#include <crtdbg.h>
int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
FILE *fileOpen;
char *buffer;
size_t dataInFile;
long filesize;
// The three structs
struct ethernet_hdr ethHdr;
struct ip_hdr ipHdr;
struct tcp_hdr tcpHDr;
fileOpen = fopen("C:\\Users\\Viktor\\source\\repos\\Laboration_3\\Laboration_3\\TCPdump", "rb");
if (fileOpen == NULL)
{
printf("Error\n");
}
else
{
printf("Success\n");
}
char lenOf[10];
size_t nr;
// Reads until \n comes
fgets(lenOf, sizeof(lenOf), fileOpen);
sscanf(lenOf, "%d", &nr);
// Withdraw the size of a package and check if it's correct
printf("Value: %d\n", nr);
printf("Adress: %d\n", &nr);
void *ptr;
fread(&ptr, nr, 1, fileOpen);
int resEth = 14;
printf("resEth: %d\n", resEth);
int resIP = IP_HL((struct ip_hdr*)ptr);
printf("ResIP: %d\n", resIP);
int resTcp = TH_OFF((struct tcp_hdr*)ptr);
printf("tcpIP: %d\n", resTcp);
int res = resEth + resIP + resTcp;
printf("Total: %d", res);
fclose(fileOpen);
//free(buffer);
system("pause");
return 0;
}
I know that the first struct ethernet will always have the size of 14 but I need to get the size of the other 2 and I'm suppose to use IP_HL and TH_OFF for that.
But my problems lies in that I can't seem to read the entire package to one
void * with the fread. I get noting in my *ptr.
Which in turn makes the code break when I try to convert the void * to one of the structs ones.
What I'm doing wrong with the void *?
Two problems:
First you should not really use text functions when reading binary files. Binary files doesn't really have "lines" in the sense that text file have it.
Secondly, with
void *ptr;
fread(&ptr, nr, 1, fileOpen);
you are passing a pointer to the pointer variable, you don't actually read anything into memory and then make ptr point to that memory. What happens now is that the fread function will read nr bytes from the file, and then write it to the memory pointed to by &ptr, which will lead to undefined behavior if nr > sizeof ptr (as then the data will be written out of bounds).
You have to allocate nr bytes of memory, and then pass a pointer to the first element of that:
char data[nr];
fread(data, nr, 1, fileOpen);
You should also get into the habit of checking for errors. What if the fread function fails? Or the file is truncated and there isn't nr bytes left to read?
You can check for these conditions by checking what fread returns.
And not only check for fread, there are more functions than fopen that can fail.
I'm working with TCP sockets. I'm sending data to the open socket using the write function.
write(Socket_Fd, "test", 4);
That works. But when I do it this way.
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char BYTE;
typedef struct LANC
{
BYTE START;
BYTE END;
} LCODE;
int main(int argc, char *argv[]){
LCODE COMMAND;
COMMAND.START = 0x28;
COMMAND.END = 0x06;
short value = (COMMAND.START << 8) | COMMAND.END;
write(socket_FD, value, sizeof(value);
return 0;
}
when I check the size of the value I get 2 bytes which is correct since i combined 0x28 and 0x06. So doing a printf.
printf("%x\n", value);
output is: 2806 which is correct.
printf("%d\n", sizeof(value);
output is: 2 bytes which is correct.
I'm getting an error when I'm trying to write the hexadecimal to the open socket using write. What am I doing wrong?
You're committing two disgusting errors in one line (how does it even compile?). You're passing an integer (value) to write() where it expects a pointer (that won't compile, you're trying to deceive us about your code). Secondly, you're doing something that's endian-dependant, that is, on different processors you'll get different results depending on whether the high-byte of "value" comes first or second in memory.
Solution:
unsigned char value[2] = {COMMAND.START, COMMAND.END};
write(socket_FD, value, sizeof(value));
I've written some code in C for converting strings passed from VBA, when the C code is called from VBA from a MacOSX dylib. I got some good hints here, and since I only care about ASCII strings I've written the following functions to convert the BSTR to a simple char*:
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "myheader.h"
size_t vbstrlen(BSTR *vbstr)
{
size_t len = 0U;
while(*(vbstr++)) ++len;
len = len*2;
return len;
}
void vbstochr(BSTR *vbstr, char** out)
{
int len2 = vbstrlen(vbstr);
char str[len+1];
int i;
for(i = 0; i < len; i++)
{
str[i] = (char) (((uint16_t*) vbstr)[i]);
}
str[i] = '\0';
asprintf(out, str);
}
int test(BSTR *arg1)
{
char* convarg;
vbstochr(arg1, &convarg);
return 1;
}
The myheader.h looks like this:
typedef uint16_t OLECHAR;
typedef OLECHAR * BSTR;
. I used uint16_t because of the 4 byte (not 2 byte) wchar_t in the MacOSX C compiler. I added a breakpoint after vbstochar is called to look at the content of convarg, and it seems to work when called from Excel.
So this works, but one thing I don't understand is why I have to multiply my len in the vbstrlen function by 2. I'm new to C, so I had to read up on pointers a little bit - and I thought since my BSTR contains 2 byte characters, I should get the right string length without having to multiply by two? It would be great if someone could explain this to me, or post a link to a tutorial?
Also, my functions with string arguments work when called in VBA, but only after the first call. So when I call a function with a BSTR* argument from a dylib for the first time (after I start the application, Excel in this case), the BSTR* pointer just points at some (random?) address, but not the string. When I call the function from VBA a second time, everything works just fine - any ideas why this is the case?!
A BSTR has an embedded length, you do not need to calculate the length manually.
As for the need to multiply the length by 2, that is because a BSTR uses 2-byte characters, but char is only 1 byte. You coded your vbstrlen() function to return the number of bytes in the BSTR, not the number of characters.
Since you are only interested in ASCII strings, you can simplify the code to the following:
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "myheader.h"
size_t vbstrlen(BSTR *vbstr)
{
if (vbstr)
return *(((uint32_t*)vbstr)-1);
return 0;
}
void vbstochr(BSTR *vbstr, char** out)
{
size_t len = vbstrlen(vbstr);
char str[len+1] = {0};
for(size_t i = 0; i < len; ++i)
str[i] = (char) vbstr[i];
asprintf(out, str);
}
The chances are that the VB string is a UTF-16 string that uses 2 bytes per character (except for characters beyond the BMP, Basic Multilingual Plane, or U+0000..U+FFFF, which are encoded as surrogate pairs). So, for your 'ASCII' data, you will have alternating ASCII characters and zero bytes. The 'multiply by 2' is because UTF-16 uses two bytes to store each counted character.
This is almost definitive when we see:
typedef uint16_t OLECHAR;
typedef OLECHAR * BSTR;