3

I need to write data to a binary file using C's I/O functions. The following code causes a runtime exception :


#include "stdio.h"

int main(int argc,char* argv[]) {
    FILE *fp = fopen("path_to_file.bin","wb");
    if(fp == NULL) {
        printf("error creating file");
        return -1;
    }
    int val = 4;
    fwrite((const void*)val,sizeof(int),1,fp);
    fclose(fp);
    return 0;
}

The code dies at the fwrite. Can you spot what I'm doing wrong? Apparently, I'm, trying to access data at 0x0000004 or something like that.

Thanks !

6 Answers 6

27

I think Neil's answer can be improved upon. I realize it's already accepted, so this is just to show some contrast (which is why I didn't just edit his).

fwrite(&val, sizeof val, 1, fp);

Two improvements:

  • No pointer casting, since it's not necessary in C and can hide errors.
  • Use sizeof directly on the object, since that is what you're passing a pointer to. Makes a lot of sense to me, and is safer than repeating yourself and using the type name.
Sign up to request clarification or add additional context in comments.

4 Comments

+1 Good points, both. Moral of the story: prefer as little casts and use sizeof judiciously.
Can you please explain why the cast isn't necessary? I'm not a C programmer ... and I would like to understand as much as possible of it's "magic".
fwrite() expects a void* as its first argument. Any pointer type can be used where a void* is expected without casting. void* effectively says "I need a pointer, I don't care what type it points to".
Not required in C. Especially with pointers. You can assign a pointer to void to a pointer to any object type and vice versa
20
 fwrite((const void*)val,sizeof(int),1,fp);

should be:

 fwrite((const void*) & val,sizeof(int),1,fp);

BTW, if you don't use the cast, you will get a sensible error message. Casts tend to be used by C (and C++) programmers far more often than they should be - a good rule of thumb is "if it needs a cast, it's probably wrong".

1 Comment

+ another 1 for that rule. i have it on a sticky note on my monitor.
5

Adding to Neil's answer: this works when you are reading and writing the file on the same platform. Things can become weird if you are reading/writing across platforms with different endianness.

2 Comments

Not only endianness, also the size may vary.
C is soo not multi platform, in the file writing/reading you need to make a implementation for each platform most times, different end of line markers and things like that become a nightmare when dealing with file writing/reading across platforms (kindda off topic anyway :P)
0
#include "stdio.h"

int main(int argc,char* argv[]) {
    FILE *fp = fopen("path_to_file.bin","wb");
    if(fp == NULL) {
        printf("error creating file");
        return -1;
    }
    int val = 4;
    fwrite((const void*)val,sizeof(int),1,fp);

You should supply an address not integer itself.

Additionaly you should not use the integer in such way:

  1. It may differ in endianess on different computers (as mentioned)
  2. It may differ in size. On really old computers it may be 1 or 2 bytes. On most modern it will be 4 but it may be 8 as well (some 64-bit computers). On some strange architectures it may be even 36 bits. int32_t val = 4; fwrite((const void *)val, 4, 1, fp) should solve the problem.

You may think that your software will never need to be ported. Well - many designers (software and hardware) made similar assumptions. Sometimes it is too costly to not make them - but in this case it is just a matter of few additional checks.

    fclose(fp);
    return 0;
}

Comments

0

I also faced this kind of problem. So this is my solution.

fwrite(val, sizeof(val[0], sizeof(val)/sizeof(val[0]), fp);

Comments

0

Apparently, I'm, trying to access data at 0x0000004 or something like that.

int val = 4

There's the issue. fwrite is designed to work with strings, and as such its first input is a pointer, the location of a string in memory. You are passing the value of val directly (4) rather than the address of val to fwrite; however, the memory at 0x00000004 is not valid program memory and thus an error is given.

To fix this, change this:

fwrite((const void*)val,sizeof(int),1,fp);

Into this:

fwrite((const void*)&val, sizeof(int), 1, fp);

The "&" operator indicates the location of val. This would be a valid address in memory.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.