<html>
<head>
<style>
.hmmessage P
{
margin:0px;
padding:0px
}
body.hmmessage
{
FONT-SIZE: 10pt;
FONT-FAMILY:Tahoma
}
</style>
</head>
<body class='hmmessage'>
So much for trying plain text to avoid truncation, darnit.<BR><BR><BR><BR>> From: jayk123@hotmail.com<BR>> To: m3devel@elegosoft.com<BR>> Subject: proposal/insistence for fixed size integer types in Ctypes.i3<BR>> Date: Sun, 1 Jun 2008 02:32:27 +0000<BR>> <BR>> <BR>> <BR>> Currently the various Utypes.i3 introduce various types LIKE<BR>> <BR>> <BR>> uint8_t = unsigned_char;<BR>> uint16_t = unsigned_short;<BR>> uint32_t = unsigned_int;<BR>> uint64_t = unsigned_long_long;<BR>> <BR>> <BR>> int8_t = signed_char;<BR>> int16_t = short;<BR>> int32_t = int;<BR>> int64_t = long_long;<BR>> <BR>> <BR>> sometimes there is an underscore after the u.<BR>> <BR>> <BR>> There is quite some variation in which, if any, of these types are provided.<BR>> When they are provided, they are always the same, with one exception I will detail.<BR>> <BR>> <BR>> Arguably they are provided only for defining other types and function signatures<BR>> within m3-libs/m3core/src/unix.<BR>> <BR>> <BR>> I strongly strongly strongly propose that at least the above 8 types go in<BR>> Ctypes, and the definitions in Utypes removed.<BR>> <BR>> <BR>> If there was more commonality in Utypes, I'd "forward" them for compatibility,<BR>> but there is little commonality. Code depending on these types would have to<BR>> be forked a lot. As I said, the types are always the same, if they are defined,<BR>> but they are often not defined.<BR>> <BR>> <BR>> One variation I am open to is introducing a new .i3 file.<BR>> But in general I like to colocate stuff rather than pick apart everything<BR>> and decide an ideal location. There are tradeoffs either way,<BR>> though most people only see the tradeoffs in the way I do it.<BR>> The tradeoffs the other way are having to track down module after module,<BR>> interface after interface, where to get stuff from, rather than having<BR>> a "one stop shop", or "fewer shops to stop".<BR>> <BR>> <BR>> I am also willing to have u_* types and CAPITALIZED types:<BR>> <BR>> <BR>> uint8_t = unsigned_char;<BR>> uint16_t = unsigned_short;<BR>> uint32_t = unsigned_int;<BR>> uint64_t = unsigned_long_long;<BR>> <BR>> <BR>> int8_t = signed_char;<BR>> int16_t = short;<BR>> int32_t = int;<BR>> int64_t = long_long;<BR>> <BR>> <BR>> u_int8_t = uint8_t;<BR>> u_int16_t = uint16_t;<BR>> u_int32_t = uint32_t;<BR>> u_int64_t = uint64_t;<BR>> <BR>> <BR>> UINT8 = uint8_t;<BR>> UINT16 = uint16_t;<BR>> UINT32 = uint32_t;<BR>> UINT64 = uint64_t;<BR>> <BR>> <BR>> INT8 = int8_t;<BR>> INT16 = int16_t;<BR>> INT32 = int32_t;<BR>> INT64 = int64_t;<BR>> <BR>> <BR>> All built-in Modula-3 types are capitalized, as all Modula-3 keywords are.<BR>> And capitalized types is a style widely used in the Windows headers.<BR>> (Windows and Modula-3 share a common heritage -- Digital -- though I don't know<BR>> from where the style of capitalized types originates.)<BR>> <BR>> <BR>> The names "int8", "int16" are also obvious candidates, but I feel that some<BR>> amount of typographical convention should be used to demark types.<BR>> Some amount of "Hungarian", if you will.<BR>> Obviously there are vehement opposing opinions on this.<BR>> "Hungarian" is often too precise and precludes changing types without<BR>> changing names, as well as producing unpronouncable names.<BR>> A "weak" form however seems reasonable and useful.<BR>> <BR>> <BR>> These types represent a certain point of view.<BR>> It is a common point of view, but not universal.<BR>> <BR>> <BR>> There are roughly three or four perspectives here:<BR>> <BR>> <BR>> 1)<BR>> char, short, int, long are abstractly defined and all code should live with it.<BR>> char is at least 8 bits, and of unspecified signedness<BR>> (limits.h defines CHAR_BIT, the number of bits in char<BR>> for specified signedness, use signed char or unsigned char;<BR>> I think char has actually three options for its signess -- signed, unsigned, or "half unsigned")<BR>> short is at least 16 bits, signed<BR>> int is at least 16 bits, signed<BR>> long is at least 32 bits, signed<BR>> <BR>> <BR>> There are not necessarily integral types that can hold pointers.<BR>> size_t and ptrdiff_t perhaps, but unclear.<BR>> size_t can hold the size of anything, but I think "anything" is "any variable"<BR>> and not necessarily "the entire address space".<BR>> <BR>> <BR>> ptrdiff_t can hold the result of subtracting pointers, but it is only<BR>> valid to subtract pointers that point into the same array or just past it.<BR>> <BR>> <BR>> It is common, for example, but not universal, for the "address space"<BR>> to be divided between "user mode" and "kernel mode", often with a 50/50 split,<BR>> so therefore size_t could be one bit smaller than a pointer, at least.<BR>> Of course that's an "unnatural" size, but theoretically possible.<BR>> (This kernel/user 50/50 split is usually exactly how 32 bit and I assume<BR>> 64 bit Windows works, though 32 bit Windows can also have a 3 gig / 1 gig split,<BR>> and 32 bit Windows code running on 64 bit Windows kernel can get a<BR>> full 4 gig address space.)<BR>> <BR>> <BR>> As well, the representation of signed integers is left unspecified.<BR>> The range of "int" need only go down to -32767, not necessarily -32768.<BR>> Signed magnitude and one's complement are valid representations.<BR>> Overflowing a signed integer causes undefined behavior.<BR>> Unsigned numbers do not have this abstraction.<BR>> <BR>> <BR>> While this is the "most correct" view, according to (my understanding) the C standard,<BR>> implementations do nail down details way beyond this, and a lot of<BR>> code depends on these details.<BR>> <BR>> <BR>> While I may have some of those details slightly wrong, you get the point.<BR>> You CAN write code within this interface, but a lot of code violates it, sometimes<BR>> <BR>> <BR>> by accident, sometimes for important practical reasons.<BR>> Some amount of code assumes an int is at least or exactly 32 bits.<BR>> Some amount of code assumes int or long can hold a pointer, though<BR>> int probably not so much, and long probably of proportionally<BR>> rapidly decreasing instance due to Win64.<BR>> <BR>> <BR>> <BR>> 2)<BR>> char, short, int, long are somewhat abstractly defined<BR>> char is exactly 8 bits<BR>> varying perspectives on its presumed signedness<BR>> short is exactly 16 bits<BR>> int is exactly 32 bits<BR>> long there are few perspectives on; it is exactly 32 bits ("Windows"), or<BR>> it is exactly the size of a pointer ("Unix"), or it is at least<BR>> the size of a pointer<BR>> <BR>> <BR>> As well, two's complement is the only representation of signed numbers<BR>> in use, and code depends on this.<BR>> <BR>> <BR>> (I recently read that we can thank the IBM S/360 or such, in the 1960's,<BR>> for introducing such modern-day architectural features that everyone<BR>> takes for granted as an 8 bit byte and two's complement signed numbers.)<BR>> <BR>> <BR>> If you need an integer with a particular exact size, either use char/short/int directly,<BR>> or run them through "autoconf", or sniff "limits.h".<BR>> <BR>> <BR>> 3) This is my recently acquired perspective, but it isn't new.<BR>> <BR>> <BR>> Given that #1 is "correct but rare", and that #2 are<BR>> full of "exact":<BR>> <BR>> <BR>> char, short, int, long are funny names with not particularly<BR>> useful specifications. #2 is a little sleazy (less so if autoconfed/limits.h)<BR>> Unless you are really adhering to the strict spec, don't use them.<BR>> If you are in fact indexing a "small" array, they might suffice,<BR>> but is it worth it? worth having these types?<BR>> <BR>> <BR>> Theory: 16 bit machines are irrelevant and 32 bit integers<BR>> are perfectly efficient on 64 bit machines, and 64 bit integers<BR>> are universally available (?) and reasonably efficient (?),<BR>> so feel free to use them if there is a need.<BR>> <BR>> <BR>> As well, 4gig remains a large capacity in most contexts, so feel<BR>> free to use explictly 32 bit integers.<BR>> <BR>> <BR>> However file sizes and offsets should really always be 64 bits.<BR>> Any code still requiring 32 bit file offsets/sizes is unfortunate.<BR>> That includes PE32+ imho, the file format for .exes/.dlls on Win64.<BR>> <BR>> <BR>> Be clear and unsleazy and adopt new names that represent well<BR>> their specification and actual use.<BR>> <BR>> <BR>> int_t is exactly n bits in size and signed<BR>> uint_t is exactly n bits in size and unsigned<BR>> some names are chosen for unsigned and signed integers with<BR>> the exact size of a pointer<BR>> For n=8,16,32 all four types exist, and probably 64.<BR>> And pointer-sized types exist.<BR>> <BR>> <BR>> If you really feel your capacity limits should scale with address space size, or need<BR>> to store a pointer in an integer, use size_t or uintptr_t or intptr_t, etc.<BR>> <BR>> <BR>> Modula-3's position here adds that INTEGER is the exact<BR>> size of a pointer and signed. It is identical to ptrdiff_t<BR>> or intptr_t. CARDINAL is the exact size but omits the bottom "half"<BR>> of the range, and does not, I believe, extend the top "half".<BR>> <BR>> <BR>> Now, I also realize, that m3-libs/m3core/src/unix is a fairly mechanical<BR>> translation of /usr/include, and /usr/include does not necessarily<BR>> take perspective #3. So the "funny" names are useful for a human<BR>> mechanical translation. But the precise names can still be used instead.<BR>> <BR>> <BR>> Here is an exception I said I would detail:<BR>> <BR>> <BR>> irix-5.2/utypes.i3:<BR>> int64_t = RECORD val := ARRAY[0..1] OF int32_t {0,0}; END;<BR>> uint64_t = int64_t;<BR>> <BR>> <BR>> This is different in at least two ways that I see.<BR>> - default initialization to zero<BR>> - 32 bit alignment instead of 64 bit alignment<BR>> <BR>> <BR>> I tend to assume that the alignment is actually wrong,<BR>> however all the uses in Usignal appear unaffected, as they are always preceded<BR>> by a mix of int64_t and an even number of int32.<BR>> Either way, it is easy enough to preserve this for compatibility.<BR>> <BR>> <BR>> I would like to continue, where easy and clear, to reduce the "size" of m3-libs/m3core/src/unix.<BR>> Making these types portable available helps that.<BR>> For example -- Uin.m3 need not be duplicated at all.<BR>> But then it either must use the presently more portable unsigned_short and unsigned,<BR>> or uint16_t and uint32_t should be made always available, either by adding them<BR>> to all the various Utypes.i3, or the one Ctypes.i3, or a new place.<BR>> <BR>> <BR>> Darwin currently has four Upthread.i3 files (one is dead), but needs either only two, or one<BR>> with the sizes abstracted out. I don't know if PPC64_DARWIN will needs its own yet,<BR>> I don't have one of these machines yet.<BR>> <BR>> <BR>> I would like to go ahead with this stuff *today*.<BR>> It takes some exertion of patience for me to stop and send this first. :)<BR>> <BR>> <BR>> - Jay<BR><BR></body>
</html>