I have a little VM for a programming language implemented in C. It supports being compiled under both 32-bit and 64-bit architectures as well as both C and C++.
I\'m try
You seem to know what you are doing, judging from the linked source code, which I took a glance at.
You said it yourself - using "specific" types makes you have more casts. That's not an optimal route to take anyway. Use int
as much as you can, for things that do not mandate a more specialized type.
The beauty of int
is that it is abstracted over the types you speak of. It is optimal in all cases where you need not expose the construct to a system unaware of int
. It is your own tool for abstracting the platform for your program(s). It may also yield you speed, size and alignment advantage, depending.
In all other cases, e.g. where you want to deliberately stay close to machine specifications, int
can and sometimes should be abandoned. Typical cases include network protocols where the data goes on the wire, and interoperability facilities - bridges of sorts between C and other languages, kernel assembly routines accessing C structures. But don't forget that sometimes you would want to in fact use int
even in these cases, as it follows platforms own "native" or preferred word size, and you might want to rely on that very property.
With platform types like uint32_t
, a kernel might want to use these (although it may not have to) in its data structures if these are accessed from both C and assembler, as the latter doesn't typically know what int
is supposed to be.
To sum up, use int
as much as possible and resort to moving from more abstract types to "machine" types (bytes/octets, words, etc) in any situation which may require so.
As to size_t
and other "usage-suggestive" types - as long as syntax follows semantics inherent to the type - say, using size_t
for well, size values of all kinds - I would not contest. But I would not liberally apply it to anything just because it is guaranteed to be the largest type (regardless if it is actually true). That's an underwater stone you don't want to be stepping on later. Code has to be self-explanatory to the degree possible, I would say - having a size_t
where none is naturally expected, would raise eyebrows, for a good reason. Use size_t
for sizes. Use offset_t
for offsets. Use [u]intN_t
for octets, words, and such things. And so on.
This is about applying semantics inherent in a particular C type, to your source code, and about the implications on the running program.
Also, as others have illustrated, don't shy away from typedef
, as it gives you the power to efficiently define your own types, an abstraction facility I personally value. A good program source code may not even expose a single int
, nevertheless relying on int
aliased behind a multitude of purpose-defined types. I am not going to cover typedef
here, the other answers hopefully will.