64-bit integers where the implementation supports max 32-bit ints

Discussion in 'C Programming' started by James Harris, Aug 5, 2013.

  1. James Harris

    James Harris Guest

    On a 16-bit C compiler which supports up to 32-bit integers but no larger
    how feasible is it to support 64-bit integer values and is there a good way
    to do so? Best I can think of is to pass structs around principally because,
    AIUI, they can be returned from functions. But is there a better way?

    Such a struct would be along the lines of

    struct custom64 {
    uint32_t low;
    uint32_t high;
    };
    typedef struct custom64 custom64_t;

    (For the 64-bit compiler this would instead be "typedef uint64_t
    custom64_t;".)

    I know I could pass around pointers-to-64-bit-integer but that would
    probably result in some cases of needing malloc to store the values and lead
    to more complexity. So structs seem better if they would work. I can live
    with some inconvenience like not being able to specify literals and not
    having printf formats for them.

    This is for writing some C where it would be a big help if some of the
    source code modules could be compiled to 16-bit object code and to 64-bit
    object code and yet still work on 64-bit integers where necessary. So if it
    were possible to write the following and just have the above different
    definitions of the custom64_t type that would be especially useful.

    custom64_t val1, val2;
    val1 = func(val2);

    I think I'll only need such explicitly long integers in rare cases and won't
    need to do much arithmetic on them so it probably wouldn't be too burdensome
    to manipulate the few references by callable routines if necessary. In other
    words I can live without

    val1 - val2

    and replace it with

    custom64_subtract(val1, val2);

    It's early days but I think the main issues will be declaring them and
    passing them to and from other functions. Arithmetic would be nice-to-have
    but I cannot see any way to do that.

    BTW, I should say I'm sure there are extensive libraries for wide number
    manipulation but they are not what I want. Something short and simple that
    will fit in a few lines would be much preferable to something pre-written
    and extensive.

    Am I on the right lines? Is there a 'standard' way to do stuff like this in
    C?

    James
    James Harris, Aug 5, 2013
    #1
    1. Advertising

  2. James Harris

    Shao Miller Guest

    Re: 64-bit integers where the implementation supports max 32-bitints

    On 8/5/2013 13:07, James Harris wrote:
    > On a 16-bit C compiler which supports up to 32-bit integers but no larger
    > how feasible is it to support 64-bit integer values and is there a good way
    > to do so? Best I can think of is to pass structs around principally because,
    > AIUI, they can be returned from functions. But is there a better way?
    >
    > Such a struct would be along the lines of
    >
    > struct custom64 {
    > uint32_t low;
    > uint32_t high;
    > };
    > typedef struct custom64 custom64_t;
    >
    > (For the 64-bit compiler this would instead be "typedef uint64_t
    > custom64_t;".)
    >
    > I know I could pass around pointers-to-64-bit-integer but that would
    > probably result in some cases of needing malloc to store the values and lead
    > to more complexity. So structs seem better if they would work. I can live
    > with some inconvenience like not being able to specify literals and not
    > having printf formats for them.
    >
    > This is for writing some C where it would be a big help if some of the
    > source code modules could be compiled to 16-bit object code and to 64-bit
    > object code and yet still work on 64-bit integers where necessary. So if it
    > were possible to write the following and just have the above different
    > definitions of the custom64_t type that would be especially useful.
    >
    > custom64_t val1, val2;
    > val1 = func(val2);
    >
    > I think I'll only need such explicitly long integers in rare cases and won't
    > need to do much arithmetic on them so it probably wouldn't be too burdensome
    > to manipulate the few references by callable routines if necessary. In other
    > words I can live without
    >
    > val1 - val2
    >
    > and replace it with
    >
    > custom64_subtract(val1, val2);
    >
    > It's early days but I think the main issues will be declaring them and
    > passing them to and from other functions. Arithmetic would be nice-to-have
    > but I cannot see any way to do that.
    >
    > BTW, I should say I'm sure there are extensive libraries for wide number
    > manipulation but they are not what I want. Something short and simple that
    > will fit in a few lines would be much preferable to something pre-written
    > and extensive.
    >
    > Am I on the right lines? Is there a 'standard' way to do stuff like this in
    > C?
    >


    Windows has 'LARGE_INTEGER', along these lines:


    http://msdn.microsoft.com/en-us/library/windows/desktop/aa383713(v=vs.85).aspx

    --
    - Shao Miller
    --
    "Thank you for the kind words; those are the kind of words I like to hear.

    Cheerily," -- Richard Harter
    Shao Miller, Aug 5, 2013
    #2
    1. Advertising

  3. James Harris <> wrote:

    > On a 16-bit C compiler which supports up to 32-bit integers but no larger
    > how feasible is it to support 64-bit integer values and is there a good way
    > to do so? Best I can think of is to pass structs around principally because,
    > AIUI, they can be returned from functions. But is there a better way?


    Struct is a fine way. Many 16 bit compilers do 32 bit operations
    by subroutine call, as it is too much work to do inline.
    (Some do + and - inline, * and / by call.)

    All are easy to write except divide. The divide algorithm is
    in Knuth's "The Art of Computer Programming", I believe volume 2,
    but you should check.

    -- glen
    glen herrmannsfeldt, Aug 5, 2013
    #3
  4. "James Harris" <> writes:
    > On a 16-bit C compiler which supports up to 32-bit integers but no larger
    > how feasible is it to support 64-bit integer values and is there a good way
    > to do so? Best I can think of is to pass structs around principally because,
    > AIUI, they can be returned from functions. But is there a better way?


    Since 1999, the ISO C standard has required the type "long long" to be
    at least 64 bits wide. Strictly speaking, if you're using a compiler
    that doesn't support "long long", then you're not using a conforming C
    compiler. To know how to work around that, you'd have to know what
    other language features it doesn't support (such as, say, passing
    structs by value).

    If you're working with a compiler that conforms reasonably well to C90,
    which didn't require long long or any 64-bit integer type, then you do
    have a lot more

    > Such a struct would be along the lines of
    >
    > struct custom64 {
    > uint32_t low;
    > uint32_t high;
    > };
    > typedef struct custom64 custom64_t;
    >
    > (For the 64-bit compiler this would instead be "typedef uint64_t
    > custom64_t;".)


    If you use "typedef uint64_t custom64_t;" for compilers that support
    64-bit integers, it will be easy to write code that assumes custom64_t
    is an integer type, which will break on your non-64-bit platform. You
    might be better off defining it as a struct with a single uint64_t
    member, and writing alternative functions/macros to perform operations
    on them.

    The name "uint32_t" was added by the same standard (C99) that mandated
    the existence of "long long". Do you have a C90 compiler that supports
    uint32_t as an extension? If not, you might need to define uint32_t
    yourself.

    If you care about the representation of your custom64_t mapping onto a
    64-bit integer, endianness is going to be an issue. You might want to
    use an #ifdef to control the order of the "low' and "high" members. If
    the representation is never stored in a file or transmitted, that
    probably doesn't matter.

    [...]

    > BTW, I should say I'm sure there are extensive libraries for wide number
    > manipulation but they are not what I want. Something short and simple that
    > will fit in a few lines would be much preferable to something pre-written
    > and extensive.
    >
    > Am I on the right lines? Is there a 'standard' way to do stuff like this in
    > C?


    Yes, I think you're on the right track. If you have 32-bit unsigned
    integers but not 64-bit unsigned integers, a struct like you've defined
    is a good way to emulate them. Implementing the operations you need is,
    of course, left as an exercise. And probably you don't need to
    implement *all* the operations; if you never divide 64-bit integers, you
    don't have to implement 64-bit division.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 5, 2013
    #4
  5. James Harris

    James Harris Guest

    "Keith Thompson" <> wrote in message
    news:...
    > "James Harris" <> writes:
    >> On a 16-bit C compiler which supports up to 32-bit integers but no larger
    >> how feasible is it to support 64-bit integer values and is there a good
    >> way
    >> to do so? Best I can think of is to pass structs around principally
    >> because,
    >> AIUI, they can be returned from functions. But is there a better way?

    >
    > Since 1999, the ISO C standard has required the type "long long" to be
    > at least 64 bits wide. Strictly speaking, if you're using a compiler
    > that doesn't support "long long", then you're not using a conforming C
    > compiler. To know how to work around that, you'd have to know what
    > other language features it doesn't support (such as, say, passing
    > structs by value).


    True. The 16-bit compiler could be a problem in this - it already has been
    in other ways. :-(

    I have checked that it does compile structs as return values ... but not run
    the code yet....

    > If you're working with a compiler that conforms reasonably well to C90,
    > which didn't require long long or any 64-bit integer type, then you do
    > have a lot more
    >
    >> Such a struct would be along the lines of
    >>
    >> struct custom64 {
    >> uint32_t low;
    >> uint32_t high;
    >> };
    >> typedef struct custom64 custom64_t;
    >>
    >> (For the 64-bit compiler this would instead be "typedef uint64_t
    >> custom64_t;".)

    >
    > If you use "typedef uint64_t custom64_t;" for compilers that support
    > 64-bit integers, it will be easy to write code that assumes custom64_t
    > is an integer type, which will break on your non-64-bit platform. You
    > might be better off defining it as a struct with a single uint64_t
    > member, and writing alternative functions/macros to perform operations
    > on them.


    Good point. I currently compile 16-bit and 32-bit at the same time but don't
    yet have a way to compile 64-bit.... Actually, having said that the 32-bit
    compiler represents 64-bit numbers as long longs (and the 16-bit compiler
    represents them as structs) so even though I am not compiling to 64-bit yet
    the issue you raised should be covered.

    FWIW the section of the header which defines the 64-bit types is currently
    as follows. It's not fully tested yet.

    /*
    * 64-bit integers
    */

    #if INT_MAX == 0x7fffffffffffffff
    typedef signed int s64_t;
    #elif LONG_MAX == 0x7fffffffffffffff
    typedef signed long s64_t;
    #elif LLONG_MAX == 0x7fffffffffffffff
    typedef signed long long s64_t;
    #else
    typedef struct {u32_t low; s32_t high;} s64_t; /* Limited use */
    #endif

    #if UINT_MAX == 0xffffffffffffffff
    typedef unsigned int u64_t;
    #elif ULONG_MAX == 0xffffffffffffffff
    typedef unsigned long u64_t;
    #elif ULLONG_MAX == 0xffffffffffffffff
    typedef unsigned long long u64_t;
    #else
    typedef struct {u32_t low; u32_t high;} u64_t; /* Limited use */
    #endif


    > The name "uint32_t" was added by the same standard (C99) that mandated
    > the existence of "long long". Do you have a C90 compiler that supports
    > uint32_t as an extension? If not, you might need to define uint32_t
    > yourself.


    The 16-bit compiler doesn't have those definitions but the 32-bit compiler
    does. So I have chosen different names and come up with a header which
    includes the following. There are similar sections for other integer widths.
    The 32-bit stuff is simpler than that for 64-bit, above.

    /*
    * 32-bit integers
    */

    #if INT_MAX == 0x7fffffff
    typedef signed int s32_t;
    #elif LONG_MAX == 0x7fffffff
    typedef signed long s32_t;
    #else
    # error "No type candidate for s32_t"
    #endif

    #if UINT_MAX == 0xffffffff
    typedef unsigned int u32_t;
    #elif ULONG_MAX == 0xffffffff
    typedef unsigned long u32_t;
    #else
    # error "No type candidate for u32_t"
    #endif

    >
    > If you care about the representation of your custom64_t mapping onto a
    > 64-bit integer, endianness is going to be an issue. You might want to
    > use an #ifdef to control the order of the "low' and "high" members. If
    > the representation is never stored in a file or transmitted, that
    > probably doesn't matter.


    FWIW I hate #ifs which select different pieces of code. They seem to me to
    be all sorts of wrong. What I am trying to do is write the code as small
    modules and pick the correct module at link time. That's a topic in itself.

    James
    James Harris, Aug 5, 2013
    #5
  6. "James Harris" <> writes:
    > "Keith Thompson" <> wrote in message
    > news:...

    [...]
    > FWIW the section of the header which defines the 64-bit types is currently
    > as follows. It's not fully tested yet.
    >
    > /*
    > * 64-bit integers
    > */
    >
    > #if INT_MAX == 0x7fffffffffffffff
    > typedef signed int s64_t;
    > #elif LONG_MAX == 0x7fffffffffffffff
    > typedef signed long s64_t;
    > #elif LLONG_MAX == 0x7fffffffffffffff
    > typedef signed long long s64_t;
    > #else
    > typedef struct {u32_t low; s32_t high;} s64_t; /* Limited use */
    > #endif


    This might cause problems if the 16-bit compiler's preprocessor can't
    handle a 64-bit constant like 0x7fffffffffffffff. I'm not sure there's
    a really good solution. But it's likely you'll only get some warnings,
    and you can ignore them as long as it selects the right definition.

    [...]
    >> The name "uint32_t" was added by the same standard (C99) that mandated
    >> the existence of "long long". Do you have a C90 compiler that supports
    >> uint32_t as an extension? If not, you might need to define uint32_t
    >> yourself.

    >
    > The 16-bit compiler doesn't have those definitions but the 32-bit compiler
    > does. So I have chosen different names and come up with a header which
    > includes the following. There are similar sections for other integer widths.
    > The 32-bit stuff is simpler than that for 64-bit, above.


    Hmm. Personally, I'd be inclined to use the *same* names defined by
    C99.

    Some years ago, Doug Gwyn wrote a collection of files under the name
    "q8" which provide an implementation of C99-specific headers (including
    <stdint.h> for use with pre-C99 compilers. They're public domain, so
    feel free to use them any way you like.

    For example:

    #if _STDC_VERSION__ >= 199901L
    #include <stdint.h>
    #else
    #include <mystdint.h>
    #endif

    You can then freely use uint32_t and friends (except, of course, that
    your uint64_t won't directly support arithmetic operations).

    [...]

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 6, 2013
    #6
  7. James Harris

    James Harris Guest

    "Keith Thompson" <> wrote in message
    news:...
    > "James Harris" <> writes:
    >> "Keith Thompson" <> wrote in message
    >> news:...

    > [...]
    >> FWIW the section of the header which defines the 64-bit types is
    >> currently
    >> as follows. It's not fully tested yet.
    >>
    >> /*
    >> * 64-bit integers
    >> */
    >>
    >> #if INT_MAX == 0x7fffffffffffffff
    >> typedef signed int s64_t;
    >> #elif LONG_MAX == 0x7fffffffffffffff
    >> typedef signed long s64_t;
    >> #elif LLONG_MAX == 0x7fffffffffffffff
    >> typedef signed long long s64_t;
    >> #else
    >> typedef struct {u32_t low; s32_t high;} s64_t; /* Limited use */
    >> #endif

    >
    > This might cause problems if the 16-bit compiler's preprocessor can't
    > handle a 64-bit constant like 0x7fffffffffffffff. I'm not sure there's
    > a really good solution. But it's likely you'll only get some warnings,
    > and you can ignore them as long as it selects the right definition.


    The 16-bit C compilers I've tried are quirky in a number of ways. For the
    case in point they don't complain about the big constants which, I agree, is
    a bit odd. Hopefully the equality comparisons would help any such compiler
    pick the else clause but I know not to rely on that working in all cases.

    It's a pity there's no such thing as a preprocessor assert to check the
    results - and, yes, I have seen various clever but convoluted attempts to
    make one.


    > [...]
    >>> The name "uint32_t" was added by the same standard (C99) that mandated
    >>> the existence of "long long". Do you have a C90 compiler that supports
    >>> uint32_t as an extension? If not, you might need to define uint32_t
    >>> yourself.

    >>
    >> The 16-bit compiler doesn't have those definitions but the 32-bit
    >> compiler
    >> does. So I have chosen different names and come up with a header which
    >> includes the following. There are similar sections for other integer
    >> widths.
    >> The 32-bit stuff is simpler than that for 64-bit, above.

    >
    > Hmm. Personally, I'd be inclined to use the *same* names defined by
    > C99.


    I could see it that way. However, at present all names are clearly distinct
    from those standard names so it's more obvious that "all errors are my own"!
    In contrast to your #if selection below I can have just a single include,
    i.e.

    #include "my header"

    I'll keep your recommendation in mind, though. I'm just trying this stuff
    out as yet and may well come to a realisation that something else is a
    better idea than what seems good at this early stage.

    > Some years ago, Doug Gwyn wrote a collection of files under the name
    > "q8" which provide an implementation of C99-specific headers (including
    > <stdint.h> for use with pre-C99 compilers. They're public domain, so
    > feel free to use them any way you like.


    I looked at that before but didn't like the way the choices were made. The
    Q8 header has lots of sections like

    #if compiler x and target y
    ....
    #elif compiler x and target z
    ....
    etc

    The Q8 selection process seems pretty fragile. As you suggest, it could be
    copied and adapted but at present I prefer the selections to be based on
    values in limits.h. That was recommended to me by folks in this newsgroup
    and works really well. It depends entirely on real values rather than values
    which should be the case for a given compiler and environment. That's got to
    be better, right!

    > For example:
    >
    > #if _STDC_VERSION__ >= 199901L
    > #include <stdint.h>
    > #else
    > #include <mystdint.h>
    > #endif
    >
    > You can then freely use uint32_t and friends (except, of course, that
    > your uint64_t won't directly support arithmetic operations).


    AIUI both <> and "" refer to implementation-defined places but wouldn't the
    above normally have mystdint.h in quotes rather than angle brackets?

    James
    James Harris, Aug 6, 2013
    #7
  8. James Harris

    James Harris Guest

    "Keith Thompson" <> wrote in message
    news:...
    > "James Harris" <> writes:
    >> "Keith Thompson" <> wrote in message
    >> news:...

    > [...]
    >> FWIW the section of the header which defines the 64-bit types is
    >> currently
    >> as follows. It's not fully tested yet.
    >>
    >> /*
    >> * 64-bit integers
    >> */
    >>
    >> #if INT_MAX == 0x7fffffffffffffff
    >> typedef signed int s64_t;
    >> #elif LONG_MAX == 0x7fffffffffffffff
    >> typedef signed long s64_t;
    >> #elif LLONG_MAX == 0x7fffffffffffffff
    >> typedef signed long long s64_t;
    >> #else
    >> typedef struct {u32_t low; s32_t high;} s64_t; /* Limited use */
    >> #endif

    >
    > This might cause problems if the 16-bit compiler's preprocessor can't
    > handle a 64-bit constant like 0x7fffffffffffffff. I'm not sure there's
    > a really good solution. But it's likely you'll only get some warnings,
    > and you can ignore them as long as it selects the right definition.


    Interestingly it *has* caused a problem - not on the 0x7f... tests but on
    those for 0xff.... From tests it seems likely that the 16-bit preprocessor
    keeps only the low 32 bits of the constant (which is understandable given
    how it will convert such a number to binary) so a string of 16 Fs matches a
    string of 8 Fs.

    Fortunately the tests against 0x7f... work properly.

    So I wonder if I could assign the unsigned values along with the signed ones
    as in the following.

    /*
    * 64-bit integers
    */

    #if INT_MAX == 0x7fffffffffffffff
    typedef signed int s64_t;
    typedef unsigned int u64_t;
    #elif LONG_MAX == 0x7fffffffffffffff
    typedef signed long s64_t;
    typedef unsigned long u64_t;
    #elif LLONG_MAX == 0x7fffffffffffffff
    typedef signed long long s64_t;
    typedef unsigned long long u64_t;
    #else
    typedef struct {u32_t low; s32_t high;} s64_t; /* Limited use */
    typedef struct {u32_t low; u32_t high;} u64_t; /* Limited use */
    #warning "Using structures for s64_t and u64_t"
    #endif

    In other words, is it safe to assume that <something>_MAX and
    U<something>_MAX will be the same size but with the top bit set on the
    latter? (If so I should probably select all signed and unsigned values in
    the same way, i.e. based on the signed maxima.)

    What fun. ;-)

    James
    James Harris, Aug 6, 2013
    #8
  9. James Harris

    James Kuyper Guest

    Re: 64-bit integers where the implementation supports max 32-bitints

    On 08/06/2013 06:15 AM, James Harris wrote:
    ....
    > It's a pity there's no such thing as a preprocessor assert to check the
    > results - and, yes, I have seen various clever but convoluted attempts to
    > make one.


    What does "preprocessor assert" mean to you, such that #if combined with
    #error fails to qualify?

    ....
    >> #if _STDC_VERSION__ >= 199901L
    >> #include <stdint.h>
    >> #else
    >> #include <mystdint.h>
    >> #endif
    >>
    >> You can then freely use uint32_t and friends (except, of course, that
    >> your uint64_t won't directly support arithmetic operations).

    >
    > AIUI both <> and "" refer to implementation-defined places but wouldn't the
    > above normally have mystdint.h in quotes rather than angle brackets?


    Yes. While the locations that are searched are implementation-defined
    for both forms, the key difference is that when you use "", it first
    searches an implementation-defined set of places, and if that search
    fails, falls back to searching the same set of places used by <>. In
    other words, "" causes a search that is at least as wide as that caused
    by <>, and on any reasonable implementation it will be a wider one,
    generally including user-specified locations. Standard headers are
    guaranteed to be found by either form, but a non-standard header might
    be found only by "", so it's generally a good idea to reserve <> for
    standard headers, and "" for everything else.
    The POSIX headers are guaranteed, by the POSIX standard, to be found by
    #include <>, so I count them as standard headers for this purpose. I
    presume other operating systems might make similar guarantees.
    --
    James Kuyper
    James Kuyper, Aug 6, 2013
    #9
  10. On Monday, August 5, 2013 10:37:40 PM UTC+1, James Harris wrote:
    > "Keith Thompson" <> wrote in message
    >
    > FWIW I hate #ifs which select different pieces of code. They seem to me to
    > be all sorts of wrong. What I am trying to do is write the code as small
    > modules and pick the correct module at link time. That's a topic in itself.
    >

    Yes, it means you have to test the code on a 16 bit compiler as well as a
    32 bit one to know that it's correct, because effectively you've got two
    programs sharing the same source file. Also the syntax is rather hard to
    read.

    stdint.h causes endless problems. ffmpeg uses it because it needs 64 bit
    types, and it breaks on Visual Studio, I suspect deliberately. But it is
    the right answer, everyone defining their own fixed-size type was worse.
    A lot of fixed-size types are used unnecessarily, but they are sometimes
    needed.

    C should have a mul() function that returns the high portion of a value.
    Most chips have a machine instruction which does this. But it doesn't, and
    it's not easy to write a portable one.
    Malcolm McLean, Aug 6, 2013
    #10
  11. James Harris

    James Harris Guest

    "James Kuyper" <> wrote in message
    news:ktqo42$i8e$...
    > On 08/06/2013 06:15 AM, James Harris wrote:
    > ...
    >> It's a pity there's no such thing as a preprocessor assert to check the
    >> results - and, yes, I have seen various clever but convoluted attempts to
    >> make one.

    >
    > What does "preprocessor assert" mean to you, such that #if combined with
    > #error fails to qualify?


    Ah, sorry - was thinking of verifying/asserting the *sizes* of the defined
    types.

    James
    James Harris, Aug 6, 2013
    #11
  12. James Harris

    James Kuyper Guest

    Re: 64-bit integers where the implementation supports max 32-bitints

    On 08/06/2013 08:59 AM, James Harris wrote:
    > "James Kuyper" <> wrote in message
    > news:ktqo42$i8e$...
    >> On 08/06/2013 06:15 AM, James Harris wrote:
    >> ...
    >>> It's a pity there's no such thing as a preprocessor assert to check the
    >>> results - and, yes, I have seen various clever but convoluted attempts to
    >>> make one.

    >>
    >> What does "preprocessor assert" mean to you, such that #if combined with
    >> #error fails to qualify?

    >
    > Ah, sorry - was thinking of verifying/asserting the *sizes* of the defined
    > types.


    OK - obviously that can't be done by a preprocessor assert, because
    types don't exist yet, so sizeof(type) is meaningless, and is converted
    into a syntax error during evaluation of #if conditions.

    However, why are you interested in the sizes? I got the impression from
    your previous messages that you were mainly interested in the ranges,
    *_MIN to *_MAX, which are available in <limits.h> and <stdint.h>, and
    are testable in #if.
    --
    James Kuyper
    James Kuyper, Aug 6, 2013
    #12
  13. James Harris

    Eric Sosman Guest

    Re: 64-bit integers where the implementation supports max 32-bitints

    On 8/5/2013 9:42 PM, Keith Thompson wrote:
    > "James Harris" <> writes:
    >> "Keith Thompson" <> wrote in message
    >> news:...

    > [...]
    >> FWIW the section of the header which defines the 64-bit types is currently
    >> as follows. It's not fully tested yet.
    >>
    >> /*
    >> * 64-bit integers
    >> */
    >>
    >> #if INT_MAX == 0x7fffffffffffffff
    >> typedef signed int s64_t;
    >> #elif LONG_MAX == 0x7fffffffffffffff
    >> typedef signed long s64_t;
    >> #elif LLONG_MAX == 0x7fffffffffffffff
    >> typedef signed long long s64_t;
    >> #else
    >> typedef struct {u32_t low; s32_t high;} s64_t; /* Limited use */
    >> #endif

    >
    > This might cause problems if the 16-bit compiler's preprocessor can't
    > handle a 64-bit constant like 0x7fffffffffffffff. I'm not sure there's
    > a really good solution. But it's likely you'll only get some warnings,
    > and you can ignore them as long as it selects the right definition.
    > [...]


    One approach is to write tests like

    #if ((INT_MAX >> 16) >> 16) == 0x7fffffff

    Details: We know that preprocessor arithmetic is equivalent to that
    of the execution environment's widest integer types, which are no
    narrower than `[unsigned] long', which are at least 32 bits wide.
    Therefore, the 16-bit shifts above are well-defined (although a
    31-bit shift of a signed value might not be), and two of them
    eliminate 32 low-order bits. Also, we know that INT_MAX is one
    less than a power of two, so if any 1-bits remain after shifting
    we can conclude that all the eliminated bits were also 1's.

    Similar arrangements like

    #if ((INT_MAX >> 30) >> 30) == 0x7

    would also work, in pretty much the same way.

    --
    Eric Sosman
    d
    Eric Sosman, Aug 6, 2013
    #13
  14. James Harris

    James Harris Guest

    "James Kuyper" <> wrote in message
    news:ktqtfq$fkb$...
    > On 08/06/2013 08:59 AM, James Harris wrote:
    >> "James Kuyper" <> wrote in message
    >> news:ktqo42$i8e$...
    >>> On 08/06/2013 06:15 AM, James Harris wrote:
    >>> ...
    >>>> It's a pity there's no such thing as a preprocessor assert to check the
    >>>> results - and, yes, I have seen various clever but convoluted attempts
    >>>> to
    >>>> make one.
    >>>
    >>> What does "preprocessor assert" mean to you, such that #if combined with
    >>> #error fails to qualify?

    >>
    >> Ah, sorry - was thinking of verifying/asserting the *sizes* of the
    >> defined
    >> types.

    >
    > OK - obviously that can't be done by a preprocessor assert, because
    > types don't exist yet, so sizeof(type) is meaningless, and is converted
    > into a syntax error during evaluation of #if conditions.
    >
    > However, why are you interested in the sizes? I got the impression from
    > your previous messages that you were mainly interested in the ranges,
    > *_MIN to *_MAX, which are available in <limits.h> and <stdint.h>, and
    > are testable in #if.


    Not quite. I am *using* the ranges in limits.h to define the sizes of
    various signed and unsigned integers, namely:

    [su]8_t
    [su]16_t
    [su]32_t
    [su]64_t

    The idea is that these can be used in the code in their own right (not all
    of my compilers have stdint.h but the project requires a lot of
    specific-sized integers) and can also be used elsewhere in headers to set
    the sizes of other integers needed in the project.

    In terms of the 'preprocessor assert' issue I was thinking it would be a
    good idea to verify that they were all the expected sizes. ATM I verify them
    by running some code as in

    $ ./a.out
    sizeof s8_t 1
    sizeof u8_t 1
    sizeof s16_t 2
    sizeof u16_t 2
    sizeof s32_t 4
    sizeof u32_t 4
    sizeof s64_t 8
    sizeof u64_t 8
    sizeof sint_t 8
    sizeof uint_t 8
    sizeof bptr_t 8

    The above set is for the 64-bit target which is why [su]int_t have size 8.
    (I believe gcc defaults to 4 byte ints on 64-bit targets.) The last one,
    bptr_t is for byte pointers.

    James
    James Harris, Aug 6, 2013
    #14
  15. On Tuesday, August 6, 2013 3:12:47 PM UTC+1, James Harris wrote:
    > "James Kuyper" <> wrote in message
    >
    > sizeof sint_t 8
    >
    > sizeof uint_t 8
    >
    > The above set is for the 64-bit target which is why [su]int_t have size 8.
    > (I believe gcc defaults to 4 byte ints on 64-bit targets.)
    >

    int should be the natural register size, which means 64 bits on a 64 bit
    system. That also means that, expect for the annoying but practically
    unimportant case of a byte array that takes up over half the memory,
    int can index any array.
    Malcolm McLean, Aug 6, 2013
    #15
  16. "James Harris" <> writes:
    > "Keith Thompson" <> wrote in message
    > news:...

    [...]
    >> For example:
    >>
    >> #if _STDC_VERSION__ >= 199901L
    >> #include <stdint.h>
    >> #else
    >> #include <mystdint.h>
    >> #endif
    >>
    >> You can then freely use uint32_t and friends (except, of course, that
    >> your uint64_t won't directly support arithmetic operations).

    >
    > AIUI both <> and "" refer to implementation-defined places but wouldn't the
    > above normally have mystdint.h in quotes rather than angle brackets?


    Yes, I should have written #include "mystdint.h".

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 6, 2013
    #16
  17. Malcolm McLean <> writes:
    > On Tuesday, August 6, 2013 3:12:47 PM UTC+1, James Harris wrote:
    >> "James Kuyper" <> wrote in message
    >>
    >> sizeof sint_t 8
    >>
    >> sizeof uint_t 8
    >>
    >> The above set is for the 64-bit target which is why [su]int_t have size 8.
    >> (I believe gcc defaults to 4 byte ints on 64-bit targets.)
    >>

    > int should be the natural register size, which means 64 bits on a 64 bit
    > system. That also means that, expect for the annoying but practically
    > unimportant case of a byte array that takes up over half the memory,
    > int can index any array.


    Perhaps it "should". Nevertheless, int is typically 32 bits on 64-bit
    systems, probably because making it 64 bits would mean you can't have
    both a 16-bit type and a 32-bit type (unless the implementation resorts
    to extended integer types).

    Perhaps it would have made sense to add a "short short" type, so you
    could have:
    char 8 bits
    short short 16 bits
    short 32 bits
    int 64 bits
    but I don't see that happening any time soon.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 6, 2013
    #17
  18. James Harris

    James Kuyper Guest

    Re: 64-bit integers where the implementation supports max 32-bitints

    On 08/06/2013 10:12 AM, James Harris wrote:
    > "James Kuyper" <> wrote in message
    > news:ktqtfq$fkb$...

    ....
    >> However, why are you interested in the sizes? I got the impression from
    >> your previous messages that you were mainly interested in the ranges,
    >> *_MIN to *_MAX, which are available in <limits.h> and <stdint.h>, and
    >> are testable in #if.

    >
    > Not quite. I am *using* the ranges in limits.h to define the sizes of
    > various signed and unsigned integers, namely:
    >
    > [su]8_t
    > [su]16_t
    > [su]32_t
    > [su]64_t
    >
    > The idea is that these can be used in the code in their own right (not all
    > of my compilers have stdint.h but the project requires a lot of
    > specific-sized integers) and can also be used elsewhere in headers to set
    > the sizes of other integers needed in the project.
    >
    > In terms of the 'preprocessor assert' issue I was thinking it would be a
    > good idea to verify that they were all the expected sizes. ...


    Well, pre-processing is translation phase 4; types don't exist, and
    therefore don't have a size, until translation phase 7, so you're
    looking for something that occurs later than pre-processing, but earlier
    than assert() itself. C2011 provides _Static_assert() for that purpose,
    but if you can't even count on support for stdint.h, I guess you can't
    use _Static_assert().
    James Kuyper, Aug 6, 2013
    #18
  19. "James Harris" <> writes:

    > "James Kuyper" <> wrote in message
    > news:ktqtfq$fkb$...
    >> On 08/06/2013 08:59 AM, James Harris wrote:
    >>> "James Kuyper" <> wrote in message
    >>> news:ktqo42$i8e$...
    >>>> On 08/06/2013 06:15 AM, James Harris wrote:
    >>>> ...
    >>>>> It's a pity there's no such thing as a preprocessor assert to check the
    >>>>> results - and, yes, I have seen various clever but convoluted attempts
    >>>>> to
    >>>>> make one.
    >>>>
    >>>> What does "preprocessor assert" mean to you, such that #if combined with
    >>>> #error fails to qualify?
    >>>
    >>> Ah, sorry - was thinking of verifying/asserting the *sizes* of the
    >>> defined
    >>> types.

    >>
    >> OK - obviously that can't be done by a preprocessor assert, because
    >> types don't exist yet, so sizeof(type) is meaningless, and is converted
    >> into a syntax error during evaluation of #if conditions.
    >>
    >> However, why are you interested in the sizes? I got the impression from
    >> your previous messages that you were mainly interested in the ranges,
    >> *_MIN to *_MAX, which are available in <limits.h> and <stdint.h>, and
    >> are testable in #if.

    >
    > Not quite. I am *using* the ranges in limits.h to define the sizes of
    > various signed and unsigned integers, namely:
    >
    > [su]8_t
    > [su]16_t
    > [su]32_t
    > [su]64_t
    >
    > The idea is that these can be used in the code in their own right (not all
    > of my compilers have stdint.h but the project requires a lot of
    > specific-sized integers) and can also be used elsewhere in headers to set
    > the sizes of other integers needed in the project.
    >
    > In terms of the 'preprocessor assert' issue I was thinking it would be a
    > good idea to verify that they were all the expected sizes. ATM I verify them
    > by running some code as in


    You can get a compile-time check by writing code that generates a
    constraint violation based on the size. There are lots of options and I
    am not sure there is any definitive "best practice" way to do it. Hers
    is just one:

    #define SA_JOIN(a, b, c) a##b##c
    #define SA_ID(p, l, s) SA_JOIN(p, l, s)
    #define STATIC_ASSERT(b) \
    struct SA_ID(assert_on_, __LINE__, _struct) { \
    int SA_ID(assert_on_line_, __LINE__, _failed) : !!(b); \
    }

    STATIC_ASSERT(sizeof(int) == 4);
    STATIC_ASSERT(sizeof(int) == 5);

    You can't guarantee good messages, but you will get something from the
    compiler. Reasonable ones will fail to compile (rather than just warn)
    when given a zero width bit-field. gcc says:

    t.c:9:1: error: zero width for bit-field 'assert_on_line_9_failed'

    <snip>
    --
    Ben.
    Ben Bacarisse, Aug 6, 2013
    #19
  20. Re: 64-bit integers where the implementation supports max 32-bitints

    On 06-Aug-13 09:19, Malcolm McLean wrote:
    > On Tuesday, August 6, 2013 3:12:47 PM UTC+1, James Harris wrote:
    >> sizeof sint_t 8
    >> sizeof uint_t 8
    >>
    >> The above set is for the 64-bit target which is why [su]int_t have
    >> size 8. (I believe gcc defaults to 4 byte ints on 64-bit targets.)

    >
    > int should be the natural register size, which means 64 bits on a 64
    > bit system.


    Of course, that assumes a useful definition of "natural". For instance,
    there are three common models for "64-bit" machines: ILP64, I32LP64 and
    IL32LLP64. And proponents of each will explain why their model is more
    "natural" than the others.

    > That also means that, expect for the annoying but practically
    > unimportant case of a byte array that takes up over half the memory,
    > int can index any array.


    That assumes an int is as wide as a void*, which is not true on I32LP64
    and IL32LLP64 systems, e.g. Linux and Windows on x86-64.

    S

    --
    Stephen Sprunk "God does not play dice." --Albert Einstein
    CCIE #3723 "God is an inveterate gambler, and He throws the
    K5SSS dice at every possible opportunity." --Stephen Hawking
    Stephen Sprunk, Aug 7, 2013
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    553
    Mark P
    Apr 3, 2005
  2. Weng Tianxiang
    Replies:
    36
    Views:
    3,413
    Brannon
    Jul 15, 2006
  3. Skybuck Flying

    ints ints ints and ints

    Skybuck Flying, Jul 8, 2004, in forum: C Programming
    Replies:
    24
    Views:
    816
    Jack Klein
    Jul 10, 2004
  4. seung

    using 64-bit integers on 32-bit machine

    seung, Sep 28, 2007, in forum: C Programming
    Replies:
    5
    Views:
    1,487
    David Thompson
    Oct 15, 2007
  5. cwdjrxyz
    Replies:
    0
    Views:
    449
    cwdjrxyz
    Oct 22, 2011
Loading...

Share This Page