1

Is there any method equivalent to c read() in c++? To illustrate my question, in C, if I have:

struct A{  
  char data[4];  
  int num;  
};

...and if I use:

A* a = malloc (sizeof(struct A));  
read (fd, a, sizeof(struct A));

I can directly populate my struct. Is there a way in c++ to achieve this without using c read() method? Methods in std::istream need char* as an argument, is there any method which takes void* as an argument?

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
sap
  • 75
  • 1
  • 1
  • 10
  • You can (reinterpret) cast any pointer to `char*`, if you're careful... – Cameron Jan 26 '14 at 05:07
  • possible duplicate: http://stackoverflow.com/questions/234724/is-it-possible-to-serialize-and-deserialize-a-class-in-c – selbie Jan 26 '14 at 05:08
  • @selbie I don't think both questions are same. – sap Jan 26 '14 at 05:17
  • @Cameron Yeah I can always do that but I was just curious whether there is any clean way of doing it or some method in c++ I am not aware of – sap Jan 26 '14 at 05:19
  • 1
    The non-portable nature of the code presented aside (ex: think about what happens when that data file is written with a 32-bit little-endian implementation, and read with a 64-bit big-endian implementation), I'm afraid if you're looking for a `void*` param for writing, you're going to have to implement your own. – WhozCraig Jan 26 '14 at 05:19
  • + 1 on what WhozCraig said. Not just endian differences, but also differences in padding rules for member alignments between members of a struct/class are different between platforms. – selbie Jan 26 '14 at 05:40
  • http://stackoverflow.com/questions/21049909/read-equivalent-for-filebuf – user2485710 Jan 26 '14 at 05:48
  • @selbie What will be the clean way of reading data directly into a struct? Or this approach of reading data directly into a struct is not good? – sap Jan 26 '14 at 06:09
  • Copying data from "disk to pointer" as your have in your example code is perfectly fine as long as you do not have plans to run on different platforms and expect the the file format to be the same. For example, if your code writes to a file on Linux, then the user copies that file to a Windows box and runs your code to read it. There's no guarantee that sizeof(struct A) is the same between both platforms. Probably ok in your example since integers like to be aligned on 4-byte boundaries. But all bets are off if "data" becomes an array of 5 chars instead of 4. – selbie Jan 26 '14 at 06:41
  • If portability is a concern, then the correct way to load/save a struct to disk is to do it "member by member". That is, read 4 bytes from the disk for "data". Then read 4 bytes for "num". Don't use "int" as a type since it's size varies between platforms. Instead, use the types in such as int32_t to declare a 4-byte integer. – selbie Jan 26 '14 at 06:44
  • Why don't you use the C read() function itself? –  Oct 01 '19 at 07:34

1 Answers1

1

The closest equivalent is almost certainly to use istream::read:

struct A {
  char data[4];
  int num;
};

A a;

std::ifstream in("somefile", std::ios::binary);

in.read((char *)&a, sizeof(a));

Note that this is equivalent to read in a number of ways you'd probably prefer it wasn't--for example, it'll probably break if you upgrade your compiler, and might break just from breathing a little wrong.

If you insist on doing it anyway, you probably at least want to hide the ugliness a little:

struct A { 
   char data[4];
   int num;

   friend std::istream &operator>>(std::istream &is, A &a) { 
       return is.read((char *)a, sizeof(a));
   }
};

Then other code will read an instance from a file with a normal insertion operator:

std::ofstream in("whatever", std::ios:;binary);

A a;

in >> a;

This way, when you come to your senses and serialize your object a little more sanely, you'll only need to modify operator>>, and the rest of the code will remain unchanged.

friend std::istream &operator>>(std::istream &is, A &a) { 
// At least deals with some of the padding problems, but not endianess, etc.
    os.read(&a.data, sizeof(a.data));
    return os.read((char *)&a.num, sizeof(a.num));
}

Then the rest of the code that uses this doesn't need to change:

A a;
in >> a;  // remains valid
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Thanks a lot. I agree that the code I posted is probably the worst way of directly populating the struct as I don't consider padding, endianness etc. Generally is it advisable to directly populate the entire struct or populate each field of struct separately? – sap Jan 26 '14 at 06:31
  • @sap: It depends on whether you care about portability, and if so to what. If possible, I'd leave that problem to outside code (e.g., use Google protocol buffers). – Jerry Coffin Jan 26 '14 at 06:33