On Mon, Feb 17, 2003 at 11:12:47AM -0700, Ray Marron wrote:
> I'm sure I'm messing it up during the save or retrieval
[...]
> typedef struct FuelsDBType
> {
> char ttype;
> UInt32 seconds; // Timestamp
> char tailno[9];
> char amount[11];
> } FuelsDBType;
>
> typedef FuelsDBType* FuelsDBPtr;
>
> #define FDB_TTYPE_START 0
> #define FDB_TTYPE_SIZE sizeof(char)
> #define FDB_SECONDS_START (FDB_TTYPE_START + FDB_TTYPE_SIZE)
> #define FDB_SECONDS_SIZE sizeof(UInt32)
> #define FDB_TAILNO_START (FDB_SECONDS_START + FDB_SECONDS_SIZE)
> #define FDB_TAILNO_SIZE 9
> #define FDB_AMOUNT_START (FDB_TAILNO_START + FDB_TAILNO_SIZE)
> #define FDB_AMOUNT_SIZE 11
>
> #define FDB_RECSIZE (FDB_AMOUNT_START + FDB_AMOUNT_SIZE)
As has been mentioned, it is the presence of unnamed padding within
your struct that has caused this discrepency. But if your code was
absolutely correctly written, it would be immune to this issue.
IMHO the real problem is that your AddToDatabase and GetFromDatabase
functions are not inverses of each other: they access the data in
entirely different ways.
> Err AddToDatabase(FuelsDBPtr recordP)
> {
[...]
> DmWrite(recP, FDB_TTYPE_START, &recordP->ttype,
> FDB_TTYPE_SIZE);
> DmWrite(recP, FDB_SECONDS_START, &recordP->seconds,
> FDB_SECONDS_SIZE);
This function writes each field separately and as a bunch of bytes,
using the *_START values that you have calculated by adding together
the sizes of the fields you have previously written. That means it's
writing a *packed* representation.
> Err GetFromDatabase(FuelsDBPtr recordP, UInt32 cursor)
> {
[...]
> recP = (FuelsDBPtr)MemHandleLock(recH);
> recordP->ttype = recP->ttype;
> recordP->seconds = recP->seconds;
> StrCopy(recordP->tailno, recP->tailno);
> StrCopy(recordP->amount, recP->amount);
This function reads each field separately but as a higher-level
(possibly aligned) object, using the layout that the compiler has chosen
for FuelsDBType in its nefarious way which is more complicated than just
adding sizes (because it needs to allow for alignment requirements,
among other things).
As usual, you can tell that you've gone wrong by the fact that you felt
that you had to use a cast :-).
If you wrote GetFromDatabase() to parallel your AddToDatabase(), all
would be well (this code is untested, of course):
Err GetFromDatabase (FuelsDBPTr recordP, UInt32 cursor) {
[...]
char *recP = MemHandleLock (recH);
MemMove (&recordP->ttype, &recP[FDB_TTYPE_START], FDB_TTYPE_SIZE);
MemMove (&recordP->seconds, &recP[FDB_SECONDS_START], FDB_SECONDS_SIZE);
[...]
Well, blah blah blah. In short, your problem was in assuming that you
could easily model the choices the compiler made in laying out the
structure. IMHO it's best to just not assume that and to write your
code as if you don't know what the structure layout looks like. Just
pretend :-).
It's okay to use your god-like knowledge to arrange your structure to
minimise padding (and the basic rule of thumb is, in the absense of
other considerations, to order your fields by size -- put the big
things, like _seconds_, first), but your code shouldn't depend on it.
That way you won't be nastily surprised if it's not what you expect.
DmWriting/MemMoving each field separately is how you read and write a
"packed" representation of your struct. And you can probably do better
with your string fields if you feel like it.
If it all seems like too much bother and you'd rather rewrite your
AddToDatabase() function to be an inverse of your existing
GetFromDatabase(), you might as well admit that you're just reading
and writing the whole struct as a unit and write them as
Err AddToDatabase (FuelsDBPtr recordP) {
[...]
DmWrite (recP, 0, recordP, sizeof (FuelsDBType));
[...]
Err GetFromDatabase (FuelsDBPtr recordP, UInt32 cursor) {
[...]
MemMove (recordP, MemHandleLock (recH), sizeof (FuelsDBType));
Then there might be unnamed padding in your database records as well,
but if you're not packing the records anyway, who really cares? :-)
Of course you won't "really know" the format of your records, but if
you're only accessing them from the one m68k program (i.e. not also from
a conduit and/or some ARM program) that doesn't really matter either.
John "and I didn't even talk about endianness :-)"
--
For information on using the Palm Developer Forums, or to unsubscribe, please see
http://www.palmos.com/dev/support/forums/