Probably not simple question

classic Classic list List threaded Threaded
39 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Probably not simple question

erw2
Hello,
I have a following problem.
In my program I have a vector of elements let say defined as follow:

struct intDouble {
? int x;
? int y;?
};

Now, I would like to put the contents of this vector into sqlite table, to
be able than read it back. Mayby someone can suggest some solution how to do
it in C++??

?

Regards
WojciechW.
Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

Austin Gilbert
I recommend using CppSQLite, see http://www.codeproject.com/database/ 
CppSQLite.asp for examples.

Austin

On Dec 7, 2005, at 1:49 PM, [hidden email] wrote:

> Hello,
> I have a following problem.
> In my program I have a vector of elements let say defined as follow:
>
> struct intDouble {
>   int x;
>   int y;
> };
>
> Now, I would like to put the contents of this vector into sqlite  
> table, to
> be able than read it back. Mayby someone can suggest some solution  
> how to do
> it in C++??
>
>
>
> Regards
> WojciechW.

Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

Nathan Kurz
In reply to this post by erw2
On Wed, Dec 07, 2005 at 08:49:42PM +0100, [hidden email] wrote:
> Hello,
> I have a following problem.
> In my program I have a vector of elements let say defined as follow:
>
> struct intDouble {
>   int x;
>   int y;
> };

It's pretty straightforward, presuming you've already figured out the
basics of connecting to the database.  You need to use 'blobs', which
are traditionally Binary Large Objects, but they can easily be small
objects as well.  Check out the documentation for:
http://www.sqlite.org/capi3ref.html#sqlite3_bind_blob and
http://www.sqlite.org/capi3ref.html#sqlite3_result_blob

To make it work in more than a superficial manner, you probably will
need a good understanding of how structures are internally represented
in C++ or C.  You pass sqlite a pointer to the struct and tell it how
long it is (using sizeof()).  When you get the blob back, you then
treat the data as an instance of your structure by casting it.

I'm not sure what level you are asking this question at, so I'm not
sure how to respond.  More background information would be helpful.

Good luck!

--nate
Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

Dan Kennedy


--- Nathan Kurz <[hidden email]> wrote:

> On Wed, Dec 07, 2005 at 08:49:42PM +0100, [hidden email] wrote:
> > Hello,
> > I have a following problem.
> > In my program I have a vector of elements let say defined as follow:
> >
> > struct intDouble {
> >   int x;
> >   int y;
> > };
>
> It's pretty straightforward, presuming you've already figured out the
> basics of connecting to the database.  You need to use 'blobs', which
> are traditionally Binary Large Objects, but they can easily be small
> objects as well.  Check out the documentation for:
> http://www.sqlite.org/capi3ref.html#sqlite3_bind_blob and
> http://www.sqlite.org/capi3ref.html#sqlite3_result_blob
>
> To make it work in more than a superficial manner, you probably will
> need a good understanding of how structures are internally represented
> in C++ or C.  You pass sqlite a pointer to the struct and tell it how
> long it is (using sizeof()).  When you get the blob back, you then
> treat the data as an instance of your structure by casting it.

I'm not sure this is always the best way to go. Any databases produced like
this will not be portable between architectures. In theory, they may not
be portable between compilers, but in practice you're probably Ok there.

Also, SQLite makes no guarantees as to the alignment of returned blobs.
This could cause a random crash somewhere down the line. You could get
around this by making a copy of the blob to memory obtained from malloc().

If at all possible, recreating the same structure as a tuple type is
almost certainly better. Although much more difficult to automate.

CREATE TABLE intDouble (x INTEGER, y INTEGER);


__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around
http://mail.yahoo.com 
Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

Nathan Kurz
On Wed, Dec 07, 2005 at 08:34:46PM -0800, Dan Kennedy wrote:
> > To make it work in more than a superficial manner, you probably will
> > need a good understanding of how structures are internally represented
> > in C++ or C.  You pass sqlite a pointer to the struct and tell it how
> > long it is (using sizeof()).  When you get the blob back, you then
> > treat the data as an instance of your structure by casting it.
>
> I'm not sure this is always the best way to go. Any databases produced like
> this will not be portable between architectures. In theory, they may not
> be portable between compilers, but in practice you're probably Ok there.

A good caveat.  If any of the members of your structure are more than
one byte long (ie, an int) this approach will fail terribly if you
create the database on a little-endian machine (Intel/PC) and then try
to use it on a little-endian one (Motorola/Mac).  But I decided to
take the question as 'How do I', rather than 'Should I'.

> Also, SQLite makes no guarantees as to the alignment of returned blobs.
> This could cause a random crash somewhere down the line. You could get
> around this by making a copy of the blob to memory obtained from malloc().

Can you offer more information about this?  In what I'm working on, I
am storing arrays of complex structures as blobs and then reconstituting
them.  I was concerned about alignment at one point, but it seems to
be working without problems.  Are there 'gotchas' that are likely to
'get me' in the future?  This is server-side, and only for temporary
data, so I'm not concerned about the endian-ness, only the alignment.

Thanks!

--nate


Reply | Threaded
Open this post in threaded view
|

Re[2]: Probably not simple question

Teg-3
Hello Nathan,

Depends on how you access them. Most RISC CPU's can't do unaligned access
to multi-byte values like int's and long, they'll segfault. Intel
CPU's don't have this problem. If you memcpy the values into place,
this is a non-issue. You see it alot with embedded CPU's.

Without knowing his environment, there's no way to guess how this
would shake out. It'll work as long as the structs don't have pointers
in them. That means anything other than naked structs won't work with
the blob technique (no strings or C++ classes). You know, there's a
whole process that I believe Microsoft calls marshalling which is used
to take structs of all sorts and send them over a wire and
re-constitute them on the other side. It's fairly complicated.

My guess is he wants to store two ints and we're getting way too
complicated but, that's just a guess.

C

Thursday, December 8, 2005, 12:52:45 AM, you wrote:

NK> On Wed, Dec 07, 2005 at 08:34:46PM -0800, Dan Kennedy wrote:
>> > To make it work in more than a superficial manner, you probably will
>> > need a good understanding of how structures are internally represented
>> > in C++ or C.  You pass sqlite a pointer to the struct and tell it how
>> > long it is (using sizeof()).  When you get the blob back, you then
>> > treat the data as an instance of your structure by casting it.
>>
>> I'm not sure this is always the best way to go. Any databases produced like
>> this will not be portable between architectures. In theory, they may not
>> be portable between compilers, but in practice you're probably Ok there.

NK> A good caveat.  If any of the members of your structure are more than
NK> one byte long (ie, an int) this approach will fail terribly if you
NK> create the database on a little-endian machine (Intel/PC) and then try
NK> to use it on a little-endian one (Motorola/Mac).  But I decided to
NK> take the question as 'How do I', rather than 'Should I'.

>> Also, SQLite makes no guarantees as to the alignment of returned blobs.
>> This could cause a random crash somewhere down the line. You could get
>> around this by making a copy of the blob to memory obtained from malloc().

NK> Can you offer more information about this?  In what I'm working on, I
NK> am storing arrays of complex structures as blobs and then reconstituting
NK> them.  I was concerned about alignment at one point, but it seems to
NK> be working without problems.  Are there 'gotchas' that are likely to
NK> 'get me' in the future?  This is server-side, and only for temporary
NK> data, so I'm not concerned about the endian-ness, only the alignment.

NK> Thanks!

NK> --nate





--
Best regards,
 Teg                            mailto:[hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

Noel Frankinet
In reply to this post by erw2
[hidden email] wrote:

>Hello,
>I have a following problem.
>In my program I have a vector of elements let say defined as follow:
>
>struct intDouble {
>  int x;
>  int y;
>};
>
>Now, I would like to put the contents of this vector into sqlite table, to
>be able than read it back. Mayby someone can suggest some solution how to do
>it in C++??
>
>
>
>Regards
>WojciechW.
>
>  
>
>------------------------------------------------------------------------
>
>No virus found in this incoming message.
>Checked by AVG Free Edition.
>Version: 7.1.371 / Virus Database: 267.13.12/193 - Release Date: 6/12/2005
>  
>
I use a blob, your class have to be able to output and be constructed by
the same blob.

Best wishes

--
No?l Frankinet
Gistek Software SA
http://www.gistek.net

Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

Dan Kennedy
In reply to this post by Nathan Kurz

typedef struct XY XY;
struct XY {
  int x;
  int y;
};

XY *pXY;


/* When retrieving values, don't do this: */
pXY = (XY *)sqlite3_column_blob(...);

/* Instead do this: */
pXY = (XY *)malloc(sizeof(XY));
memcpy(pXY, sqlite3_column_bloc(...), sizeof(XY));





--- Nathan Kurz <[hidden email]> wrote:

> On Wed, Dec 07, 2005 at 08:34:46PM -0800, Dan Kennedy wrote:
> > > To make it work in more than a superficial manner, you probably will
> > > need a good understanding of how structures are internally represented
> > > in C++ or C.  You pass sqlite a pointer to the struct and tell it how
> > > long it is (using sizeof()).  When you get the blob back, you then
> > > treat the data as an instance of your structure by casting it.
> >
> > I'm not sure this is always the best way to go. Any databases produced like
> > this will not be portable between architectures. In theory, they may not
> > be portable between compilers, but in practice you're probably Ok there.
>
> A good caveat.  If any of the members of your structure are more than
> one byte long (ie, an int) this approach will fail terribly if you
> create the database on a little-endian machine (Intel/PC) and then try
> to use it on a little-endian one (Motorola/Mac).  But I decided to
> take the question as 'How do I', rather than 'Should I'.
>
> > Also, SQLite makes no guarantees as to the alignment of returned blobs.
> > This could cause a random crash somewhere down the line. You could get
> > around this by making a copy of the blob to memory obtained from malloc().
>
> Can you offer more information about this?  In what I'm working on, I
> am storing arrays of complex structures as blobs and then reconstituting
> them.  I was concerned about alignment at one point, but it seems to
> be working without problems.  Are there 'gotchas' that are likely to
> 'get me' in the future?  This is server-side, and only for temporary
> data, so I'm not concerned about the endian-ness, only the alignment.
>
> Thanks!
>
> --nate
>
>
>


__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around
http://mail.yahoo.com 
Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

D. Richard Hipp
In reply to this post by erw2
Nathan Kurz <[hidden email]> wrote:

> > Also, SQLite makes no guarantees as to the alignment of returned blobs.
> > This could cause a random crash somewhere down the line. You could get
> > around this by making a copy of the blob to memory obtained from malloc().
>
> Can you offer more information about this?  In what I'm working on, I
> am storing arrays of complex structures as blobs and then reconstituting
> them.  I was concerned about alignment at one point, but it seems to
> be working without problems.  Are there 'gotchas' that are likely to
> 'get me' in the future?  This is server-side, and only for temporary
> data, so I'm not concerned about the endian-ness, only the alignment.
>

The address of the first byte of a BLOB or text string can be
anything.  It need not be a multiple of 2 or 4 or 8 as is required
by some (most) processors for larger data structures.  SQLite
assumes that all strings and BLOBs are an array of bytes that
can begin on an odd byte.

Actually, short blobs and strings - less than 32 bytes - or long
blobs and strings - greater than about 1000 bytes - will always
be 4- or 8-byte aligned depending on the requirements of the host
computer.  It is only those middle-length strings and blobs that
give a problem.  Nevertheless, 33 to 999 bytes is a reasonably
common string length...

This turns out to be a bug in the current implementation
when dealing with UTF16 strings.  SQLite can return a UTF16 string
that is not aligned on an even byte boundary. Some processors
get very upset about that.  This bug has only recently been
noticed, however, despite being in the code since the very
beginning of UTF16 support, so apparently most of the people
who actually use UTF16 are doing so on chips that allow odd-byte
alignment of UTF16 text.
--
D. Richard Hipp <[hidden email]>

Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

erw2
In reply to this post by erw2
I have follow your advice and had a look at CppSQLite. setBinary and
getBinary functions work only on unsigned char, and size of intDouble is
(on my PC) 8 bytes, so much more than unsigned char (1 byte).
The question is how to correctly store such structure in db, and how to
restore it later?

Regards
WojciechW

Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

Noel Frankinet
erw2 wrote:

>I have follow your advice and had a look at CppSQLite. setBinary and
>getBinary functions work only on unsigned char, and size of intDouble is
>(on my PC) 8 bytes, so much more than unsigned char (1 byte).
>The question is how to correctly store such structure in db, and how to
>restore it later?
>
>Regards
>WojciechW
>
>
>
>  
>

Hello,
when storing, create a blob from your structure and store it.
When retrieving, validate the blob (by its size, by a magic number at
the end or something like that) then feed the blob into malloced memory
and you get your object back (even if its a collection of objects)

Best wishes,

--
No?l Frankinet
Gistek Software SA
http://www.gistek.net

Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

Wilson Yeung
In reply to this post by erw2
The setBinary() method takes two arguments, the unsigned char * the
size of the blob as a size_t.

You're expected to cast your structure into an unsigned char *,
because in C/C++, the only portable way to represent a byte is with a
char/unsigned char.  And really, what is your structure but a sequence
of bytes?

So, for example:

  struct intDouble myIntDouble;
  myIntDouble.x = 1;
  myIntDouble.y = 2;

  CppSQLiteBinary blob;
  blob.setBinary((unsigned char *) myIntDouble, sizeof(struct intDouble));

SQLite is really no different than many other SQL databases in this
respect, and I think you would be better off picking up a book on SQL,
walking through a tutorial on SQL, and SQL database usage, learning
about indexes, datatypes, blobs, transactions, etc.

This mailing list can certainly answer questions about SQLite, how
it's different than other databases, and how to use SQLite
specifically.   But this mailing list probably isn't going to do a
good job at showing you how to use a SQL database in general.

Cheers,

Wilson
Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

Wilson Yeung
Oops.

Line below should read:

blob.setBinary((unsigned char *) &myIntDouble, sizeof(struct intDouble));


On 12/8/05, Wilson Yeung <[hidden email]> wrote:

> The setBinary() method takes two arguments, the unsigned char * the
> size of the blob as a size_t.
>
> You're expected to cast your structure into an unsigned char *,
> because in C/C++, the only portable way to represent a byte is with a
> char/unsigned char.  And really, what is your structure but a sequence
> of bytes?
>
> So, for example:
>
>   struct intDouble myIntDouble;
>   myIntDouble.x = 1;
>   myIntDouble.y = 2;
>
>   CppSQLiteBinary blob;
>   blob.setBinary((unsigned char *) myIntDouble, sizeof(struct intDouble));
>
> SQLite is really no different than many other SQL databases in this
> respect, and I think you would be better off picking up a book on SQL,
> walking through a tutorial on SQL, and SQL database usage, learning
> about indexes, datatypes, blobs, transactions, etc.
>
> This mailing list can certainly answer questions about SQLite, how
> it's different than other databases, and how to use SQLite
> specifically.   But this mailing list probably isn't going to do a
> good job at showing you how to use a SQL database in general.
>
> Cheers,
>
> Wilson
>
Reply | Threaded
Open this post in threaded view
|

RE: Probably not simple question

erw2
In reply to this post by Wilson Yeung
Hallo,
Thanks a lot, finally everything works well. Indeed, I have to learn
much about SQL database usage, so sorry for that question.

Regards
WojciechW

-----Original Message-----
From: Wilson Yeung [mailto:[hidden email]]
Sent: Thursday, December 08, 2005 7:38 PM
To: [hidden email]
Cc: [hidden email]
Subject: Re: [sqlite] Probably not simple question

The setBinary() method takes two arguments, the unsigned char * the
size of the blob as a size_t.

You're expected to cast your structure into an unsigned char *,
because in C/C++, the only portable way to represent a byte is with a
char/unsigned char.  And really, what is your structure but a sequence
of bytes?

So, for example:

  struct intDouble myIntDouble;
  myIntDouble.x = 1;
  myIntDouble.y = 2;

  CppSQLiteBinary blob;
  blob.setBinary((unsigned char *) myIntDouble, sizeof(struct
intDouble));

SQLite is really no different than many other SQL databases in this
respect, and I think you would be better off picking up a book on SQL,
walking through a tutorial on SQL, and SQL database usage, learning
about indexes, datatypes, blobs, transactions, etc.

This mailing list can certainly answer questions about SQLite, how
it's different than other databases, and how to use SQLite
specifically.   But this mailing list probably isn't going to do a
good job at showing you how to use a SQL database in general.

Cheers,

Wilson

Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

Allan Wind
In reply to this post by Wilson Yeung
On 2005-12-08T10:37:36-0800, Wilson Yeung wrote:
> You're expected to cast your structure into an unsigned char *,
> because in C/C++, the only portable way to represent a byte is with a
> char/unsigned char.

Off-topic, I suppose, but what is a portable representation of a byte?
What does unsigned char pointer give you that a void pointer does not
(other than support for legacy compilers)?


/Allan
Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

Wilson Yeung
I don't know of a portable representation of a byte other than a char.
 And while no one promises that a char is really a byte, I expect that
too much code would break and so it would be many many years before
this is changed in practice.

Likewise, no one promises that sizeof(int) == 4, but vendors haven't
changed this to 8 on 64 bit platforms either, opting instead to use
"long long" or "long int".

AFAIK there's nothing wrong with using void *, and most of the C
runtime functions like malloc use this.  C++, however, explicitly
disallows pointer arithmetic on a void *, so if you're programming in
C++, you may end up casting to a char * anyway.

On GNU/Linux I might include /usr/include/stdint.h, which typedefs
char to "int8_t" but, once again, AFAIK, there's no guarantee that
stdint.h is going to exist on every platform.

Wilson

On 12/8/05, Allan Wind <[hidden email]> wrote:

> On 2005-12-08T10:37:36-0800, Wilson Yeung wrote:
> > You're expected to cast your structure into an unsigned char *,
> > because in C/C++, the only portable way to represent a byte is with a
> > char/unsigned char.
>
> Off-topic, I suppose, but what is a portable representation of a byte?
> What does unsigned char pointer give you that a void pointer does not
> (other than support for legacy compilers)?
>
>
> /Allan
>
Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

i-love-spam
Wilson Yeung wrote:
> I don't know of a portable representation of a byte other than a char.
>  And while no one promises that a char is really a byte, I expect that
> too much code would break and so it would be many many years before
> this is changed in practice.

c++ *guaranties* that char is always one byte. It cannot be anything
else. The difference is that from c++ point of view byte is not limited
to 8 bits (it could be more, but not less). Not sure about c, but I
expect it be the same

>
> Likewise, no one promises that sizeof(int) == 4, but vendors haven't
> changed this to 8 on 64 bit platforms either, opting instead to use
> "long long" or "long int".

Why would you think that sizeof(int) is 4?? It's only happens to be so
on your machine/compiler. It only says that sizeof(int) is at least 2
bytes. Sizeof(long) at least 4... (AFAIK)


>
> AFAIK there's nothing wrong with using void *, and most of the C
> runtime functions like malloc use this.  C++, however, explicitly
> disallows pointer arithmetic on a void *, so if you're programming in
> C++, you may end up casting to a char * anyway.

For me pointer arrifmetic on void* makes no sense. How is the address of
the next void should be calculated (pvoid + 1) without knowing size of
void???


Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

i-love-spam
In reply to this post by Teg-3
Teg wrote:

> Hello Nathan,
>
> Depends on how you access them. Most RISC CPU's can't do unaligned access
> to multi-byte values like int's and long, they'll segfault. Intel
> CPU's don't have this problem. If you memcpy the values into place,
> this is a non-issue. You see it alot with embedded CPU's.
>
> Without knowing his environment, there's no way to guess how this
> would shake out. It'll work as long as the structs don't have pointers
> in them. That means anything other than naked structs won't work with
> the blob technique (no strings or C++ classes). You know, there's a
> whole process that I believe Microsoft calls marshalling which is used
> to take structs of all sorts and send them over a wire and
> re-constitute them on the other side. It's fairly complicated.
>
> My guess is he wants to store two ints and we're getting way too
> complicated but, that's just a guess.


     In fact, it's very simple to have multibyte values to be put into blobs
(or, simply, some binary strings/buffers). IMHO, it's almost always a
very bad decision to use memcpy for a couple of ints (alignment &
padding problems for structs). Better, write some small functions that
print/read data to/from binary strings. What is more interesting is to
be able to store complex objects, where you have pointers to dynamically
allocated objects etc., that's where things get hairy...
     I don't know about what's microsoft's marshalling is, but this all
comes down to a task known as serialization and that's the real solution
to all such problems where you want store arbitrary data in blobs or
whatever. For c++ I use boost::serialization and I can put quite crazy
(multiple inherited & polymorphic) big objects into sqlite without even
knowing how to to put PODs into sqlite blobs





Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

i-love-spam
In reply to this post by Teg-3
Teg wrote:

> Hello Nathan,
>
> Depends on how you access them. Most RISC CPU's can't do unaligned access
> to multi-byte values like int's and long, they'll segfault. Intel
> CPU's don't have this problem. If you memcpy the values into place,
> this is a non-issue. You see it alot with embedded CPU's.
>
> Without knowing his environment, there's no way to guess how this
> would shake out. It'll work as long as the structs don't have pointers
> in them. That means anything other than naked structs won't work with
> the blob technique (no strings or C++ classes). You know, there's a
> whole process that I believe Microsoft calls marshalling which is used
> to take structs of all sorts and send them over a wire and
> re-constitute them on the other side. It's fairly complicated.
>
> My guess is he wants to store two ints and we're getting way too
> complicated but, that's just a guess.


        In fact, it's very simple to have multibyte values to be put into blobs
(or, simply, some binary strings/buffers). IMHO, it's almost always a
very bad decision to use memcpy for a couple of ints (alignment &
padding problems for structs). Better, write some small functions that
print/read data to/from binary strings. What is more interesting is to
be able to store complex objects, where you have pointers to dynamically
allocated objects etc., that's where things get hairy...
        I don't know about what's microsoft's marshalling is, but this all
comes down to a task known as serialization and that's the real solution
to all such problems where you want store arbitrary data in blobs or
whatever. For c++ I use boost::serialization and I can put quite crazy
(multiple inherited & polymorphic) big objects into sqlite without even
knowing how to to put PODs into sqlite blobs
Reply | Threaded
Open this post in threaded view
|

Re: Probably not simple question

i-love-spam
In reply to this post by i-love-spam
Wilson Yeung wrote:
>>c++ *guaranties* that char is always one byte. It cannot be anything
>>else. The difference is that from c++ point of view byte is not limited
>>to 8 bits (it could be more, but not less). Not sure about c, but I
>>expect it be the same
>
>
> The definition of a byte as 8 bits is not likely to change in the next
> 20 years.  Once again, too much code would break.  Can you find one
> example in the last 15 years of a byte which is not an octet?

Byte is always 8 bits :)
just because you are programming for windows and/or for intell processor
doesn't mean that there are no other architecures out there. Why so
strange number 15 yrs? do you think that all that non 8-bit bytes were
on ancient mainframes or what?? I'm not going to look for examples, just
read c++ faq, if you haven't read so far...
http://www.parashift.com/c++-faq-lite/intrinsic-types.html


>>
>>Why would you think that sizeof(int) is 4?? It's only happens to be so
>>on your machine/compiler. It only says that sizeof(int) is at least 2
>>bytes. Sizeof(long) at least 4... (AFAIK)
>
>
> I don't think this.  Like I said, "no one promises that sizeof(int) ==
> 4".  But it is on 32 bit machines and it is on 64 bit machines too.
> And it won't be changing any time soon.  If you can give me a real
> example of a 32 bit or 64 bit platform where sizeof(int) != 4, I would
> be very surprised.

World is not limited to 32 & 64 bit. (and I don't mean that sizeof(int)
!= 4 for only 16-bit machines)
What about some specialized hardware, satelites etc... they may have
something different. And this is not realated to 32 & 64 bit at all.
This is compiler dependent.

>
> I am aware of what the standard guarantees, and also aware of what's
> true in practice.  The best one can do is introduce some typedefs,
> like what's in usr/include/stdint.h, but at the end of the day, you're
> depending on an int to be 32 bits.

You'd be safer to depend on long int, which is at least 4 bytes.

>
> Compiler vendors like gcc have defined sizeof(void) == 1, and pointer
> arithmetic on a void * is defined thusly.
>
Maybe it's defined as 1 byte, but what I care is that it doesn't make
sense to me to do arithmetics with void pointers. That's it
12