Vector of tables, flatbuffers C - c

I'm experimenting with flatbuffers, in C, just getting a feel for it. I'm having a weird issue. Well, a couple more than likely.
I think I'm building the flatbuffers and adding all the correct components in the correct manner. However, when I try to read a vector of tables, _vec_len(T) is returning size 0, even though when I hexdump the buffer I can clearly see the said tables being added to/removed from the buffer.
I've used more methods of getting the vector of tables to be readable than I can count. Most have ended with type mismatch compile errors. None of the ones that have actually compiled have resulted in _vec_len(T) returning anything other than 0.
I've also tried using _vec_at(0), but this causes an assertion to fail stating that the given index is out of range.
At this point, I'm either: a) missing something really simple, b) building the flatbuffer completely wrong, or c) making assumptions about how flatbuffers are built that are just plain incorrect.
I have attached my schema and source code, as well as debugging output from the program.
(I realized after posting that the code blocks dont include line numbers.)
The line that seems to be failing is size_t hops_vec_len = TransitHop_vec_len(hopsTable); in the C code, near the bottom. Either that, or the entire block starting at // test_root routing near the top is wrong.
By my understanding, using _start(B) and _end(B), everything that gets added to said component of the schema should be added to the buffer and placed into the v-tables for access automatically.
So, I'm not sure where to go. Can anyone point to what I'm doing wrong/misunderstanding? Any help is greatly appreciated.
flatbuffers_test.fbs
table Ping {
sent:uint;
}
table Pong {
sent:uint;
}
union Type {
Ping,
Pong,
}
enum ServerTypes:ubyte {
mach = 0,
cnc,
mill,
press,
drill,
controller,
unknown,
}
table TransitHop {
serverID: uint64;
serverType: ServerTypes;
}
table TransitHeader {
from: TransitHop;
to: TransitHop;
hops: [TransitHop];
}
table TransitSequence {
transitID: uint64;
begin: uint8;
current: uint8;
total: uint8;
}
table TestRoot {
type: Type;
sequence: TransitSequence;
routing: TransitHeader;
}
root_type TestRoot;
flatbuffers_test.c
#include <stdio.h>
#include "flatcc/support/hexdump.h"
#include "flatbuffers_test_builder.h"
// This allows us to verify result in optimized builds.
#define test_assert(x) do { if (!(x)) { assert(0); return -1; }} while(0)
int main(void) {
flatcc_builder_t builder, *B;
B = &builder;
void *buff = NULL;
size_t size;
FILE *fh = NULL;
flatcc_builder_init(B);
printf("TestRoot - Routing\n\n");
TestRoot_start_as_root(B);
{
// test_root type
{
Ping_ref_t testType = Ping_create(B, 0); // the 0 here would be the time the ping is sent
TestRoot_type_add(B, Type_as_Ping(testType));
}
// test_root sequence
{
TransitSequence_ref_t sequence = TransitSequence_create(B, 1, 1, 1, 1);
TestRoot_sequence_add(B, sequence);
}
// test_root routing
{
TransitHeader_start(B);
{
TransitHop_ref_t hopFrom = 0;
TransitHop_ref_t hopTo = 0;
TransitHeader_hops_start(B);
{
hopFrom = TransitHop_create(B, 1, ServerTypes_mach);
TransitHop_create(B, 2, ServerTypes_controller);
TransitHop_create(B, 3, ServerTypes_controller);
hopTo = TransitHop_create(B, 4, ServerTypes_cnc);
}
TransitHop_ref_t hops = TransitHeader_hops_end(B);
TransitHeader_from_add(B, hopFrom);
TransitHeader_to_add(B, hopTo);
TransitHeader_hops_add(B, hops);
}
TransitHeader_ref_t routing = TransitHeader_end(B);
TestRoot_routing_add(B, routing);
}
}
TestRoot_end_as_root(B);
buff = flatcc_builder_finalize_aligned_buffer(&builder, &size);
printf("flatbuffer size: %ld\n", size);
TestRoot_table_t test_root = TestRoot_as_root(buff);
test_assert(test_root != 0);
int type_present = TestRoot_type_is_present(test_root);
int sequence_present = TestRoot_sequence_is_present(test_root);
int routing_present = TestRoot_routing_is_present(test_root);
printf(" type present: %d\n", type_present);
if (type_present == 1) {
Type_union_type_t type = TestRoot_type_type(test_root);
printf("\ttype: %s\n", Type_type_name(type));
}
printf("sequence present: %d\n", sequence_present);
if (sequence_present == 1) {
TransitSequence_table_t sequence = TestRoot_sequence(test_root);
printf("\ttransitID: %ld\n", TransitSequence_transitID(sequence));
printf("\t begin: %d\n", TransitSequence_begin(sequence));
printf("\t current: %d\n", TransitSequence_current(sequence));
printf("\t total: %d\n", TransitSequence_total(sequence));
}
printf(" routing present: %d\n", routing_present);
if (routing_present == 1) {
TransitHeader_table_t routing = TestRoot_routing(test_root);
TransitHop_table_t from = TransitHeader_from(routing);
TransitHop_table_t to = TransitHeader_to(routing);
TransitHop_vec_t hopsTable = TransitHeader_hops(routing);
test_assert(hopsTable != 0);
ServerTypes_enum_t serverTypeFrom = TransitHop_serverType(from);
ServerTypes_enum_t serverTypeTo = TransitHop_serverType(to);
printf("\tfrom: %ld\t%s\n", TransitHop_serverID(from), ServerTypes_name(serverTypeFrom));
printf("\t to: %ld\t%s\n", TransitHop_serverID(to), ServerTypes_name(serverTypeTo));
int hops_present = TransitHeader_hops_is_present(routing);
if (hops_present == 1) {
// // this causes [Assertion `flatbuffers_vec_len(vec) > (i) && "index out of range"' failed.] ?????
// TransitHop_table_t hopsTableZero = TransitHop_vec_at(hopsTable, 0);
//
// test_assert(hopsTableZero == 0);
size_t hops_vec_len = TransitHop_vec_len(hopsTable);
printf("\thops: %lu\n", hops_vec_len);
for (size_t i = 0; i < hops_vec_len; i++) {
printf("\t\t%lu\n", i);
}
}
}
fh = fopen("/tmp/fbhd-test1", "w");
if (fh == NULL) {
printf("Cannot open /tmp/fbhd-test1 for writing\n\n");
return -1;
} else {
hexdump(NULL, buff, size, fh);
}
fclose(fh);
flatcc_builder_aligned_free(buff);
return 0;
}
debug1.txt
Program output with the vector of tables being added to the flatbuffer:
TestRoot - Routing
flatbuffer size: 188
type present: 1
type: Ping
sequence present: 1
transitID: 1
begin: 1
current: 1
total: 1
routing present: 1
from: 1 mach
to: 4 cnc
hops: 0
00000000 0c 00 00 00 54 45 53 54 00 00 00 00 5c ff ff ff |....TEST....\...|
00000010 01 00 00 00 70 00 00 00 5c 00 00 00 04 00 00 00 |....p...\.......|
00000020 7a ff ff ff 0c 00 00 00 3c 00 00 00 08 00 00 00 |z.......<.......|
00000030 00 00 00 00 96 ff ff ff 04 00 00 00 00 00 00 00 |................|
00000040 01 00 00 00 a6 ff ff ff 03 00 00 00 00 00 00 00 |................|
00000050 05 00 00 00 b6 ff ff ff 02 00 00 00 00 00 00 00 |................|
00000060 05 00 00 00 cc ff ff ff 01 00 00 00 00 00 00 00 |................|
00000070 00 00 00 00 e8 ff ff ff 01 00 00 00 00 00 00 00 |................|
00000080 01 01 01 00 fc ff ff ff 04 00 04 00 0c 00 0f 00 |................|
00000090 04 00 0c 00 0d 00 0e 00 06 00 0c 00 04 00 08 00 |................|
000000a0 0d 00 04 00 0c 00 0a 00 10 00 08 00 0c 00 04 00 |................|
000000b0 0c 00 14 00 04 00 08 00 0c 00 10 00 |............|
Program output without the vector of tables being added to the flatbuffer:
TestRoot - Routing
flatbuffer size: 74
type present: 1
type: Ping
sequence present: 1
transitID: 1
begin: 1
current: 1
total: 1
routing present: 0
00000000 0c 00 00 00 54 45 53 54 00 00 00 00 cc ff ff ff |....TEST........|
00000010 01 00 00 00 18 00 00 00 04 00 00 00 e8 ff ff ff |................|
00000020 01 00 00 00 00 00 00 00 01 01 01 00 fc ff ff ff |................|
00000030 04 00 04 00 0c 00 0f 00 04 00 0c 00 0d 00 0e 00 |................|
00000040 0a 00 10 00 04 00 08 00 0c 00 |..........|
Program output when trying to use _vec_at(0):
TestRoot - Routing
flatbuffer size: 188
type present: 1
type: Ping
sequence present: 1
transitID: 1
begin: 1
current: 1
total: 1
routing present: 1
from: 1 mach
to: 4 cnc
flatbuffers_test: /home/vadtec/schema/generated/flatbuffers_test_reader.h:192: TransitHop_vec_at: Assertion `flatbuffers_vec_len(vec) > (i) && "index out of range"' failed.

I received a response from the flatcc author.
See https://groups.google.com/g/flatbuffers/c/mjkyhbA6vS8 for the complete response.

Related

Confusing error when writing structure to file in C

i'm trying to write a structure to a dat file, everything works fine but the data in the dat file turns into random characters (it's the same in other formats like txt)
#include <stdio.h>
#include <string.h>
struct Product
{
char ProId[20];
char ProName[30];
float Price;
int Quantity;
int CatId;
};
int main(){
FILE *f;
f = fopen ("Product.dat", "w+");
if (f == NULL)
{
fprintf(stderr, "\nError opened file\n");
}
Product p1;
strcpy(p1.ProId, "1");
strcpy(p1.ProName, "Candy");
p1.Price = 4.5;
p1.Quantity = 5;
p1.CatId = 1;
fwrite(&p1, sizeof(p1), 1, f);
fclose(f);
return(0);
}
The data in Product.dat:
1 u ÿÿÿÿCandy Ù$# #
I tried searching for this error but to no avail. Please help me, what is wrong?
Thank you.
I compile and ran your code on my WSL2, and met the same problem, here is the hexdump:
00000000 31 00 00 00 00 00 00 00 e7 6a 5b 66 fd 7f 00 00 |1........j[f....|
00000010 e6 6a 5b 66 43 61 6e 64 79 00 d4 1a 18 56 00 00 |.j[fCandy....V..|
00000020 e8 32 96 dd 70 7f 00 00 80 12 d4 1a 18 56 00 00 |.2..p........V..|
00000030 00 00 00 00 00 00 90 40 05 00 00 00 01 00 00 00 |.......#........|
The string "Candy" is indeed copied to the struct.
I assume the reason it is polluted by some trash data is because this struct is allocated on stack.
So I made a clean up after the declaration of this struct, and here is the effect:
00000000 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |1...............|
00000010 00 00 00 00 43 61 6e 64 79 00 00 00 00 00 00 00 |....Candy.......|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 90 40 05 00 00 00 01 00 00 00 |.......#........|
Here is the code I modified, note the call to memset():
#include <stdio.h>
#include <string.h>
struct Product
{
char ProId[20];
char ProName[30];
float Price;
int Quantity;
int CatId;
};
int main(){
FILE *f;
f = fopen ("Product.dat", "w+");
if (f == NULL)
{
fprintf(stderr, "\nError opened file\n");
}
struct Product p1;
memset(&p1, 0, sizeof(p1));
strcpy(p1.ProId, "1");
strcpy(p1.ProName, "Candy");
p1.Price = 4.5;
p1.Quantity = 5;
p1.CatId = 1;
fwrite(&p1, sizeof(p1), 1, f);
fclose(f);
return(0);
}

C hexadecimal formatting giving me extra digits

I've been working on a small program to dump the hex values of a file, similar to od or hexdump, and I've ran into an issue when printing the values. For certain hex values, mostly ones with alphabetical characters as their second digit, it prints with 6 extra f digits before printing the actual number, instead of just printing a 2-width value like I had specified. I have confirmed that the values themselves are not unexpected in any way, it's the printing that's messing it up.
Code:
int main(int argc, char* argv[]) {
FILE* dataFile = fopen(argv[1], "rb");
int byteCount = 0;
char currentByte = fgetc(dataFile);
while (currentByte != EOF) {
printf("%08d", byteCount);
do {
//print as hex
printf(" %02x ", currentByte);
//set up for next loop
currentByte = fgetc(dataFile);
byteCount++;
} while (currentByte != EOF && (byteCount) % 16 != 0);
printf("\n");
}
printf("%08d\n", byteCount);
}
Output:
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
00000016 03 00 3e 00 01 00 00 00 10 6b 00 00 00 00 00 00
00000032 40 00 00 00 00 00 00 00 08 23 02 00 00 00 00 00
00000048 00 00 00 00 40 00 38 00 0d 00 40 00 1f 00 1e 00
00000064 06 00 00 00 04 00 00 00 40 00 00 00 00 00 00 00
00000080 40 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00
00000096 ffffffd8 02 00 00 00 00 00 00 ffffffd8 02 00 00 00 00 00 00
00000112 08 00 00 00 00 00 00 00 03 00 00 00 04 00 00 00
00000128 18 03 00 00 00 00 00 00 18 03 00 00 00 00 00 00
00000144 18 03 00 00 00 00 00 00 1c 00 00 00 00 00 00 00
00000160 1c 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
00000176 01 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00
00000192 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000208 fffffff8 34 00 00 00 00 00 00 fffffff8 34 00 00 00 00 00 00
Does anyone know what's going on here?
There are several problems here.
char is entirely unsuitable to hold raw binary data, because it has implementation-defined signedness and it often a signed type, see Is char signed or unsigned by default?. In fact char should only ever be used for text strings. Instead, you would normally use uint8_t. However... :
The EOF constant is of type int, so if you intend to compare something against EOF, it must be type int. fgetc is guaranteed to return characters as if they were unsigned char but converted to int - as it happens, int is large enough to hold all values of an unsigned char so int can be used here.
%x specifier for printf expects an unsigned int.
Fixes:
char currentByte -> int currentByte
printf(" %02x ", currentByte); -> printf(" %02x ", (unsigned int)currentByte);.
You must always check if fopen was successful and also fclose the file pointer when done. Also note that calling fopen directly on argv with no input sanitation is not acceptable in a professional program. You don't even know if argv[1] exists - the program needs a whole lot more error handling overall.

Trying to read bitmap file as hexadecimals

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define NBRCOLOURS 16
#define COLOURSIZE 8
typedef struct
{
char colours[COLOURSIZE];
}BITMAP;
//Main Function
void main(void)
{
int count, count2;
char bm_file[] = "C:\\Coding\\Bitmap Program\\Sample.bmp";
FILE *fptr;
char ch;
int i = 0;
BITMAP bm_data[NBRCOLOURS];
fptr = fopen(bm_file, "rb");
if (fptr != NULL)
{
while ((ch = fgetc(fptr)) != EOF)
{
printf("%02X ", ch);
if (!(++i % 16)) putc('\n', stdout);
}
}
fclose(fptr);
system("pause");
return;
}
I am using this code which I found mostly online to try and read the contents of a bitmap file as its hexadecimal values. For some reason, this code stops right at the end of the header, and unfortunately ultimately I need to count the number of times each colour appears so that I can figure out which occurs most and which occurs least.
If anyone could tell me why this code stops at the end of the header for the bitmap, or lead me towards being able to pull the rest of the hexadecimal data out of the file, I would really appreciate it.
Here is the hex code:
42 4D C6 00 00 00 00 00 00 00 76 00 00 00 28 00
00 00 0A 00 00 00 0A 00 00 00 01 00 04 00 00 00
00 00 50 00 00 00 12 0B 00 00 12 0B 00 00 10 00
00 00 10 00 00 00 FF 00 00 00 00 FF 00 00 00 00
42 00 5A 5A 84 00 00 00 FF 00 FF 00 FF 00 00 FF
FF 00 08 FF FF 00 5A FF FF 00 FF FF FF 00 FF FF
FF 00 FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF
FF 00 FF FF FF 00 92 59 00 16 47 00 00 00 25 90
01 64 61 00 00 00 59 90 11 64 61 00 00 00 99 00
16 48 11 00 00 00 90 01 64 61 11 00 00 00 00 16
64 61 00 00 00 00 01 16 46 10 09 00 00 00 11 64
41 00 99 00 00 00 16 64 11 09 95 00 00 00 66 48
10 09 53 00 00 00
And here is what prints:
42 4D FFFFFFC6 00 00 00 00 00 00 00 76 00 00 00 28 00
00 00 0A 00 00 00 0A 00 00 00 01 00 04 00 00 00
00 00 50 00 00 00 12 0B 00 00 12 0B 00 00 10 00
00 00 10 00 00 00
Long post, I'm sorry. Any help is greatly appreciated.
fgetc returns an int, not a char. You can't represent EOF with a char, as all of the possible values of a char are valid. EOF is (I think) -1 represented as an int, or 0xfffffff, so if you read 0xff as a char it's the same as EOF.
Change this:
char ch;
to:
int ch;
The number before a format specifier in printf, like %02X only guarantees a minimum number of characters outputted, not a maximum. fgetc returns an int, not a char. If the int is negative two's complement then the entire bitstring representing the int will get printed, including the FF bytes at the start. EOF is not representable as a char; only as an int.
In your case we know that the file we're working with is small enough that loading the entire file into a buffer will probably succeed, so we can just use malloc and free instead:
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char byte;
int main(int argc, char *argv[])
{
FILE *fp = fopen("C:\\Coding\\Bitmap Program\\Sample.bmp", "rb");
byte *buffer = NULL;
size_t len;
int i;
fseek(fp, 0, SEEK_END);
len = ftell(fp);
rewind(fp);
buffer = malloc(len);
if(!buffer)
{
perror("malloc");
exit(EXIT_FAILURE);
}
fread(buffer, 1, len, fp);
fclose(fp);
for(i = 0; i < len; i++)
{
if(i%16==0) putchar('\n');
printf("%.2X ", buffer[i]&0xFF);
}
free(buffer);
return 0;
}

Save audio stream in file using C libwebsockets

I have a C server that uses libwebsockets and I want to save a received audio stream in a file on disk.
Here is my code snippet:
#define FILENAME "/home/ubuntu/Desktop/file.wav"
FILE *received_file;
struct lws_context *Audiocontext;
static int callback_audio(
struct lws *wsi,
enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
{
printf("client is connected\n");
received_file = fopen(FILENAME, "w+");
if (received_file == NULL)
{
printf("Failed to open file\n");
exit(EXIT_FAILURE);
}
}
break;
case LWS_CALLBACK_RECEIVE: {
if(strcmp((char*)in,"EOS")==0)
{
printf("End of stream!\n");
fclose(received_file);
}
else
{
fwrite(in, 1, len, received_file);
}
}
}
}
I got the message "client is connected" and also the file, but the content isn't ok, I cannot play it. I think there is a problem regarding the way I save the stream on file using fwrite().
The client is sending audio chunks encoded as wav, 16Khz, mono. Here is a snippet from client (it's a javascript client, the full code is here:http://kaljurand.github.io/dictate.js/).
if (recorder) {
recorder.stop();
config.onEvent(MSG_STOP, 'Stopped recording');
// Push the remaining audio to the server
recorder.export16kMono(function(blob) {
socketSend(blob);
socketSend(TAG_END_OF_SENTENCE);
recorder.clear();
}, 'export16kMono');
config.onEndOfSpeech();
} else {
config.onError(ERR_AUDIO, "Recorder undefined");
}
The client is working well, I use it for exactly the same task, but using a Java server. I would appreciate if someone could indicate me how to save these audio chunks in a valid file.
I think that you do not write header in your wav file. To do so,
you can write some function to do so see specification here
or you can use a dedicaded library, like libsndfile, which is not so complicated to use:
// instead of fopen, write something like
SF_INFO info;
SNDFILE * sf;
info.samplerate = sample_rate;
info.channels = 1;
info.sections = 1;
info.seekable = 0;
info.frames = 0;
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
sf = sf_open(filename, SFM_WRITE, &info);
// instead of fwrite, something like
sf_write_short(sf, in, len / sizeof(short));
// and instead of fclose
sf_close(sf);
I didn't use libsndfile, but I change something on the client side. This is the current hexdump output:
00000000 52 49 46 46 20 60 00 00 57 41 56 45 66 6d 74 20 |RIFF `..WAVEfmt |
00000010 10 00 00 00 01 00 02 00 44 ac 00 00 10 b1 02 00 |........D.......|
00000020 04 00 10 00 64 61 74 61 00 60 00 00 00 00 00 00 |....data.`......|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00006020 00 00 00 00 00 00 00 00 00 00 00 00 52 49 46 46 |............RIFF|
00006030 20 60 00 00 57 41 56 45 66 6d 74 20 10 00 00 00 | `..WAVEfmt ....|
00006040 01 00 02 00 44 ac 00 00 10 b1 02 00 04 00 10 00 |....D...........|
00006050 64 61 74 61 00 60 00 00 00 00 00 00 00 00 00 00 |data.`..........|
00006060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
0000c050 00 00 00 00 00 00 00 00 52 49 46 46 20 60 00 00 |........RIFF `..|
0000c060 57 41 56 45 66 6d 74 20 10 00 00 00 01 00 02 00 |WAVEfmt ........|
0000c070 44 ac 00 00 10 b1 02 00 04 00 10 00 64 61 74 61 |D...........data|
0000c080 00 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.`..............|
0000c090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
It seems to be wav encoded, but i don't have a content.

How can I write a structure to a file ?

I have tried to look this up in multiple places and I cannot understand why fwrite doesn't work.
If I had a structure with 100 fields I would not want to use fprintf with 100 format specifiers.
struct emp
{
char name[15];
int age;
int salary;
char address[30];
};
int main()
{
char str[60];
struct emp emp1[5] = {{"Yoda",23,45000,"Asia"},{"Darth",34,2344,"NAmerica"},{"Jabba",22,5566,"Africa"},{"Luke",33,3399,"SAmerica"},{"Laya",44,6677,"Europe"}};
FILE *fp;
fp = fopen("C:/.../sampleText.txt","w");`
int i=0;
for(i=0; i<5; i++)
{
fwrite(&emp1[i],sizeof(emp1[i]),1,fp);
//fprintf(fp,"%s, %d, %d, %s\n",&emp1[i].name,emp1[i].age,emp1[i].salary,emp1[i].address);
}
fclose(fp);
getch();
}
There are two answers:
It does work, if everything is set correctly and porting the written data to other machines is not an issue.
It doesn't work if you have any of a large number of common features in data structures, or if you need to move the data from one type of machine (say an Intel machine) to another type (say PowerPC or SPARC).
In your example structure, you have no pointers, so you could write the structure verbatim to a file, and then in another invocation of the program running on the same (type of) machine, you could read it back in, and you would see the same data.
However, if your structure contained pointers, you could not meaningfully write the structure to disk. The pointers in one invocation of the program need not have any significance in another invocation of the program. If you needed to port the data between a little-endian (Intel) and big-endian (PowerPC, SPARC) machine, you'd have to use a platform-neutral way of accessing the data; simply writing the data to disk would not work.
So, where portability is not an issue, this code should work — Unix or Windows. It uses the "wb" and "rb" arguments to fopen() because the data is binary data, not plain text. The b is optional but harmless on Unix; it is crucial on Windows. The code also fixes the file name to sampledata.bin so it can be run on either platform, writing in the current directory. It writes the data; it then reads the data; it then compares the read data with the written data, reporting any problems. If the program says nothing, all is OK.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct emp
{
char name[15];
int age;
int salary;
char address[30];
};
int main(void)
{
char const filename[] = "sampledata.bin";
struct emp emp1[5] =
{
{ "Yoda", 23, 45000, "Asia" },
{ "Darth", 34, 2344, "N America" },
{ "Jabba", 22, 5566, "Africa" },
{ "Luke", 33, 3399, "S America" },
{ "Leia", 44, 6677, "Europe" },
};
struct emp emp2[5];
FILE *ifp;
FILE *ofp;
int i;
ofp = fopen(filename, "wb");
if (ofp != 0)
{
if (fwrite(emp1, sizeof(emp1), 1, ofp) != 1)
{
fprintf(stderr, "Failed to write to %s\n", filename);
exit(1);
}
fclose(ofp);
}
ifp = fopen(filename, "rb");
if (ifp != 0)
{
if (fread(emp2, sizeof(emp2), 1, ifp) != 1)
{
fprintf(stderr, "Failed to read from %s\n", filename);
exit(1);
}
fclose(ifp);
}
for (i = 0; i < 5; i++)
{
if (emp1[i].age != emp2[i].age ||
emp1[i].salary != emp2[i].salary ||
strcmp(emp1[i].name, emp2[i].name) != 0 ||
strcmp(emp1[i].address, emp2[i].address) != 0)
printf("Difference in record %d\n", i);
}
return 0;
}
Content of the file sampledata.bin:
0x0000: 59 6F 64 61 00 00 00 00 00 00 00 00 00 00 00 00 Yoda............
0x0010: 17 00 00 00 C8 AF 00 00 41 73 69 61 00 00 00 00 ........Asia....
0x0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030: 00 00 00 00 00 00 00 00 44 61 72 74 68 00 00 00 ........Darth...
0x0040: 00 00 00 00 00 00 00 00 22 00 00 00 28 09 00 00 ........"...(...
0x0050: 4E 20 41 6D 65 72 69 63 61 00 00 00 00 00 00 00 N America.......
0x0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0070: 4A 61 62 62 61 00 00 00 00 00 00 00 00 00 00 00 Jabba...........
0x0080: 16 00 00 00 BE 15 00 00 41 66 72 69 63 61 00 00 ........Africa..
0x0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00A0: 00 00 00 00 00 00 00 00 4C 75 6B 65 00 00 00 00 ........Luke....
0x00B0: 00 00 00 00 00 00 00 00 21 00 00 00 47 0D 00 00 ........!...G...
0x00C0: 53 20 41 6D 65 72 69 63 61 00 00 00 00 00 00 00 S America.......
0x00D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00E0: 4C 65 69 61 00 00 00 00 00 00 00 00 00 00 00 00 Leia............
0x00F0: 2C 00 00 00 15 1A 00 00 45 75 72 6F 70 65 00 00 ,.......Europe..
0x0100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0110: 00 00 00 00 00 00 00 00 ........
0x0118:
You don't specify what you mean by fwrite doesn't work, but I'll assume you're working on Windows, in which case you need to specify "wb" to fopen. By default on Windows, it's writing in text mode (i.e. "wt").
not a good idea to write struct to file or sockets as it is. It is inviting complex to solve problems. the best approach is to use serialization before writing. Also, as Jim pointed out above, make sure to open the file in binary.
Take a look in this question and the answers. there is a pretty good answer and explanation for your question.
Passing a structure through Sockets in C
Data serialization is a non-trivial task. As some others have pointed out, it is possible in some cases to write the contents of your struct to disk as binary data. It's the simplest to write, but it is unlikely to be stable. Each time you recompile your code, it can potentially change the format the data is written and read in.
Your best option is to use a standard data interchange format, such as CSV, XML, or JSON. There are many existing tools to utilize these formats, so you should look into using one of them.

Resources