K
Keith Thompson
Roose said:OK, suppose you want to serialize a group of structs, which contain pointersn
to each other (a graph). In game programming, for getting data into the
game, it's a common idiom to subtract the base address in the PC tools,
store it on disk, and rebind the pointers at runtime in the game engine by
adding back a new base address. You can't do that without understanding the
equivalence, since of course you only read ints from binary files at first.
Of course this is not portable, but it works on 3 game consoles, and I would
contend that there is way to the exact same thing on ANY platform (with the
bit masking/arithmetic being slightly different, etc.)
If all the structs are part of a single object (e.g., a single chunk
of memory allocated by malloc()), the kind of thing you describe can
be done portably. For each pointer, cast it to char* and subtract the
base address of the enclosing object to get the byte offset of the
object referenced by the pointer.
On the other hand, if it's not practical for all your structs to be
part of the same object (e.g., you want to malloc() them individually)
the kind of mapping and serialization you describe would depend on the
details of how malloc() allocates memory. I don't know enough about
the inner workings of typical heap implementations to know whether
this would be practical, but I suspect there's enough variation to
make it difficult.
You mention subtracting the base address; where does this base address
come from?
If non-portable code really is the best solution for your application,
by all means write non-portable code. Wherever possible, keep it
isolated in a small number of modules, and write the majority of your
application as portably as you can. This will make your job easier
when you need to port it to another platform; the code you have to
modify will be small and contained.
I don't think anybody here has claimed that all C code must be
strictly conforming, or that non-portable code is evil. Non-portable
code is sometimes necessary. But I've found that clean code tends to
be portable, and vice versa. If you develop the right habits, writing
portable code really isn't all that difficult. But when you write
code that depends on the characteristics of a particular system,
you've left the scope of this newsgroup, and if you have any questions
about it, you're more likely to get correct answers in a newsgroup
devoted to that system.
[...]
Can you explain how an error in not writing standard C might result in such
a bug?
Not specifically, but imagine a program that operates on a pointer in
a manner that only works if pointers are just integers. When the
program is ported to a system where that's not the case, it generates
pointer values that point to random locations in memory. If it writes
a value through such a pointer, it can clobber some arbitrary
variable. Sometimes this may be harmless, but sometimes, depending on
the circumstances, the result can be drastic.
Failure to check against buffer overflow is actually a much more
common way for this kind of thing to happen, but anything that might
generate an invalid pointer value can cause problems like this.