Use of Long and Long Long

Discussion in 'C Programming' started by Bart C, Jan 9, 2008.

  1. Bart C

    Bart C Guest

    I've always had a problem knowing exactly how wide my integer variables were
    in C, and the little program below has increased my confusion.

    Run on 3 compilers on the same cpu (32-bit pentium), sometimes int and long
    int are the same, and long long int is twice the width; or sometimes both
    long int and long long int are twice the width of int.

    This apparently all quite normal according to my c99 draft and c-faq.com.
    However it doesn't alter the fact that this is all very 'woolly' and
    ambiguous.

    Integer widths that obey the rule short < int < long int <long long int
    (instead of short<=int<=long int or whatever) would be far more intuitive
    and much more useful (as it is now, changing int x to long int x is not
    guaranteed to change anything, so is pointless)

    Given that I know my target hardware has an 8-bit byte size and natural word
    size of 32-bits, what int prefixes do I use to span the range 16, 32 and
    64-bits? And perhaps stay the same when compiled for 64-bit target?

    Is there any danger of long long int ending up as 128-bits? Sometimes I
    might need 64-bits but don't want the overheads of 128.

    Or should I just give up and use int32_t and so on, and hope these are
    implemented in the compiler?

    (Haven't seen anything similar for floating point in my C99 draft, but it
    seems better behaved, except for long double which gives results of 96 or
    128 below (neither of which match the 80-bits of my cpu).)

    Thanks,

    Bart

    #include <stdio.h>
    #include <stdlib.h>
    #include <limits.h>

    int main(void)
    {
    char c;
    short int si;
    short s;
    int i;
    long l;
    long int li;
    long long int lli;
    float f;
    double d;
    long double ld;

    printf("C = %3d bits\n",sizeof(c)*CHAR_BIT);
    printf("SI = %3d bits\n",sizeof(si)*CHAR_BIT);
    printf("S = %3d bits\n",sizeof(s)*CHAR_BIT);
    printf("I = %3d bits\n",sizeof(i)*CHAR_BIT);
    printf("L = %3d bits\n",sizeof(l)*CHAR_BIT);
    printf("LI = %3d bits\n",sizeof(li)*CHAR_BIT);
    printf("LLI = %3d bits\n",sizeof(lli)*CHAR_BIT);
    printf("\n");
    printf("F = %3d bits\n",sizeof(f)*CHAR_BIT);
    printf("D = %3d bits\n",sizeof(d)*CHAR_BIT);
    printf("LD = %3d bits\n",sizeof(ld)*CHAR_BIT);

    }
    Bart C, Jan 9, 2008
    #1
    1. Advertising

  2. Bart C

    Guest

    On Jan 9, 10:33 pm, "Bart C" <> wrote:
    > This apparently all quite normal according to my c99 draft and c-faq.com.
    > However it doesn't alter the fact that this is all very 'woolly' and
    > ambiguous.

    As long as they can represent the minimum value for MIN/MAX they are
    okay.

    > Integer widths that obey the rule short < int < long int <long long int
    > (instead of short<=int<=long int or whatever) would be far more intuitive

    If you are talking about sizes, there is no such rule.
    Here are the evaluation rules for sizeof:
    sizeof (char) == 1
    sizeof (anything) >= 1 && sizeof (anything) <= SIZE_MAX
    > and much more useful (as it is now, changing int x to long int x is not
    > guaranteed to change anything, so is pointless)

    Very little is guaranteed, but I don't see the problem here.
    You can use <stdint.h> and (u)intN_t where N is 8,16,32,64. You may
    find that does not guarantee much either.
    > Is there any danger of long long int ending up as 128-bits? Sometimes I
    > might need 64-bits but don't want the overheads of 128.

    If your application needs exactly 64 bits, yes there is 'danger'.
    > Or should I just give up and use int32_t and so on, and hope these are
    > implemented in the compiler?

    They usually are.
    > #include <stdio.h>
    > #include <stdlib.h>
    > #include <limits.h>
    >
    > int main(void)
    > {
    > char c;
    > short int si;
    > short s;

    shirt int and short are the same.
    > int i;
    > long l;
    > long int li;

    ditto for long and long int.
    > long long int lli;
    > float f;
    > double d;
    > long double ld;
    > printf("C = %3d bits\n",sizeof(c)*CHAR_BIT);
    > printf("SI = %3d bits\n",sizeof(si)*CHAR_BIT);
    > printf("S = %3d bits\n",sizeof(s)*CHAR_BIT);
    > printf("I = %3d bits\n",sizeof(i)*CHAR_BIT);
    > printf("L = %3d bits\n",sizeof(l)*CHAR_BIT);
    > printf("LI = %3d bits\n",sizeof(li)*CHAR_BIT);
    > printf("LLI = %3d bits\n",sizeof(lli)*CHAR_BIT);
    > printf("\n");
    > printf("F = %3d bits\n",sizeof(f)*CHAR_BIT);
    > printf("D = %3d bits\n",sizeof(d)*CHAR_BIT);
    > printf("LD = %3d bits\n",sizeof(ld)*CHAR_BIT);
    >
    > }

    You invoke undefined behavior here.
    The proper format specifier for size_t is '%zu'

    'sizeof (type) * CHAR_BIT' is not an accurate way to calculate the
    number of bits 'type' uses in your system.
    , Jan 9, 2008
    #2
    1. Advertising

  3. Bart C

    Flash Gordon Guest

    Bart C wrote, On 09/01/08 20:33:
    > I've always had a problem knowing exactly how wide my integer variables were
    > in C, and the little program below has increased my confusion.
    >
    > Run on 3 compilers on the same cpu (32-bit pentium), sometimes int and long
    > int are the same, and long long int is twice the width; or sometimes both
    > long int and long long int are twice the width of int.


    This is allowed.

    > This apparently all quite normal according to my c99 draft and c-faq.com.


    Correct.

    > However it doesn't alter the fact that this is all very 'woolly' and
    > ambiguous.


    The "natural size" bit is wolly and leave a lot of "wiggle room".
    Generally however the OS specifies an ABI (Application Binary Interface)
    which specifies such thing.

    > Integer widths that obey the rule short < int < long int <long long int
    > (instead of short<=int<=long int or whatever) would be far more intuitive
    > and much more useful (as it is now, changing int x to long int x is not
    > guaranteed to change anything, so is pointless)


    Now look at a 32 bit DSP which cannot deal with anything below 32 bits.
    Given your definition it would have to do at least
    sizeof(char) == 1 - 32 bits
    sizeof(short) == 2 - 64 bits
    sizeof(int) == 3 - 96 bits
    sizeof(long) == 4 - 128 bits
    sizeof(long long) == 5 - 156 bits

    So on such a processor you have probably just made anything larger than
    short (including int) of no use for most purposes. Certainly it would
    mean that when writing SW of the DSP you would end up using char for
    almost everything where you would expect to use int.

    > Given that I know my target hardware has an 8-bit byte size and natural word
    > size of 32-bits, what int prefixes do I use to span the range 16, 32 and
    > 64-bits? And perhaps stay the same when compiled for 64-bit target?


    If those are your minimum requirements then you use
    char - at least 8 bits
    short - at least 16 bits
    int - at least 16 bits (but likely to be larger)
    long - at least 32 bits
    long long - at least 64 bits

    Alternatively, use the types defined in stdint.h (or inttypes.h) which
    have been added in C99. These headers provide you exact width types
    (where supported by the implementation, but won't give you a 16 bit type
    if none exists), the smallest types with at least a given number of bits
    and the fastest types with at least a given number of bits.

    > Is there any danger of long long int ending up as 128-bits?


    Yes.

    > Sometimes I
    > might need 64-bits but don't want the overheads of 128.


    What if the processor does not support anything smaller than 128 bits?

    > Or should I just give up and use int32_t and so on, and hope these are
    > implemented in the compiler?


    Or the least_ or fast_ types as appropriate.

    > (Haven't seen anything similar for floating point in my C99 draft, but it


    There isn't.

    > seems better behaved, except for long double which gives results of 96 or
    > 128 below (neither of which match the 80-bits of my cpu).)


    <snip>

    Possibly padding added for efficiency.
    --
    Flash Gordon
    Flash Gordon, Jan 9, 2008
    #3
  4. Bart C

    user923005 Guest

    On Jan 9, 12:33 pm, "Bart C" <> wrote:
    > I've always had a problem knowing exactly how wide my integer variables were
    > in C, and the little program below has increased my confusion.
    >
    > Run on 3 compilers on the same cpu (32-bit pentium), sometimes int and long
    > int are the same, and long long int is twice the width; or sometimes both
    > long int and long long int are twice the width of int.
    >
    > This apparently all quite normal according to my c99 draft and c-faq.com.
    > However it doesn't alter the fact that this is all very 'woolly' and
    > ambiguous.
    >
    > Integer widths that obey the rule short < int < long int <long long int
    > (instead of short<=int<=long int or whatever) would be far more intuitive
    > and much more useful (as it is now, changing int x to long int x is not
    > guaranteed to change anything, so is pointless)
    >
    > Given that I know my target hardware has an 8-bit byte size and natural word
    > size of 32-bits, what int prefixes do I use to span the range 16, 32 and
    > 64-bits? And perhaps stay the same when compiled for 64-bit target?
    >
    > Is there any danger of long long int ending up as 128-bits? Sometimes I
    > might need 64-bits but don't want the overheads of 128.
    >
    > Or should I just give up and use int32_t and so on, and hope these are
    > implemented in the compiler?
    >
    > (Haven't seen anything similar for floating point in my C99 draft, but it
    > seems better behaved, except for long double which gives results of 96 or
    > 128 below (neither of which match the 80-bits of my cpu).)
    >
    > Thanks,
    >
    > Bart
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    > #include <limits.h>
    >
    > int main(void)
    > {
    > char c;
    > short int si;
    > short s;
    > int i;
    > long l;
    > long int li;
    > long long int lli;
    > float f;
    > double d;
    > long double ld;
    >
    > printf("C   = %3d bits\n",sizeof(c)*CHAR_BIT);
    > printf("SI  = %3d bits\n",sizeof(si)*CHAR_BIT);
    > printf("S   = %3d bits\n",sizeof(s)*CHAR_BIT);
    > printf("I   = %3d bits\n",sizeof(i)*CHAR_BIT);
    > printf("L   = %3d bits\n",sizeof(l)*CHAR_BIT);
    > printf("LI  = %3d bits\n",sizeof(li)*CHAR_BIT);
    > printf("LLI = %3d bits\n",sizeof(lli)*CHAR_BIT);
    > printf("\n");
    > printf("F   = %3d bits\n",sizeof(f)*CHAR_BIT);
    > printf("D   = %3d bits\n",sizeof(d)*CHAR_BIT);
    > printf("LD  = %3d bits\n",sizeof(ld)*CHAR_BIT);
    >
    >
    >
    > }- Hide quoted text -
    >
    > - Show quoted text -


    Your method is not accurate. It is possible to have trap bits or
    unused bits (e.g. IBM 360 had 32 bits but only used 24 bits for some
    types). There are also bits to represent NAN and INF for the floating
    point, and the amount of bits dedicated to mantissa and exponent can
    differ even for a data type with the same physical width in bits (e.g.
    DFLOAT and GFLOAT on OpenVMS).

    If you need exact bit sizes, then you should use the specific macros
    in C99 that map to exact bit sizes.

    Helpful things for you include:
    <stdint.h>
    <float.h>
    <limits.h>
    user923005, Jan 9, 2008
    #4
  5. Bart C

    Eric Sosman Guest

    Bart C wrote:
    > I've always had a problem knowing exactly how wide my integer variables were
    > in C, and the little program below has increased my confusion.
    >
    > Run on 3 compilers on the same cpu (32-bit pentium), sometimes int and long
    > int are the same, and long long int is twice the width; or sometimes both
    > long int and long long int are twice the width of int.
    >
    > This apparently all quite normal according to my c99 draft and c-faq.com.
    > However it doesn't alter the fact that this is all very 'woolly' and
    > ambiguous.


    Woolly perhaps, but not ambiguous. Or perhaps I don't
    comprehend the ambiguity you detect; could you explain it
    further?

    > Integer widths that obey the rule short < int < long int <long long int
    > (instead of short<=int<=long int or whatever) would be far more intuitive
    > and much more useful (as it is now, changing int x to long int x is not
    > guaranteed to change anything, so is pointless)


    Changing `char' to `unsigned long long' is not guaranteed
    to change anything either. (It certainly changes the type,
    but it seems you mean "change" to signify a difference in range,
    precision, representation, and such.)

    Keep in mind C's origins as a systems programming language
    with a need to be "close to the metal." The first metal it
    ran on was the Digital PDP-11, which had just two sizes of
    integers: 8-bit and 16-bit, mapped to `char' and `int'. Ritchie
    doesn't say when `short' appeared as a type distinct from `int',
    but by 1978 all four of `char', `short', `int', and `long' were
    part of the language. And the idea was for an implementor to
    map these types to the machine's capabilities in ways that
    seemed convenient for the system at hand.

    Until the mid-1990's few machines had enough distinct integer
    sizes to make full use of even this much freedom. Most supported
    three widths, and made `int' effectively synonymous with one of
    `short' or `long'. Implementors chose with regard to the nature
    of the hardware and of the existing software C would want to
    interoperate with. When machines started deploying a native 64-bit
    type, the obvious choice was to map the widths 8, 16, 32, 64 to
    `char', `short', `int', and `long'.

    ... and some C implementors did so, and were met with howls
    of outrage. It turned out that an enormous number of programmers
    thought `int' and `long' were the same as a matter of Natural Law,
    and had been less than scrupulous about keeping them distinct.
    The 64-bit `long' broke their sloppy code, and they were more
    willing to blame the audacious C vendor than themselves. (There
    was a similar fracas when a different environment grew `int' from
    16 to 32 bits and broke its equivalence with `short', but the
    sloppy programmers in that camp got less sympathy.) So the obvious
    "four widths, four types" mapping gained but few followers, and
    eventually the bletcherous `long long' was foisted onto C as a sop
    to all those sloppy programmers who couldn't keep `long' and `int'
    straight.

    (I've never understood why people who believed `int' and `long'
    were identical would bother to write `long': thirty-three percent
    more keystrokes for no gain -- where's the sense in that?)

    Anyhow, the point of all this is that C's mapping of types
    to hardware or to hardware/software was flexible from the git-go,
    thus removing (or declining to erect) barriers to C's adoption.
    Your desire for five different integer widths would certainly
    impose a burden in C implementations for machines not so richly
    endowed in hardware -- which is to say, practically all machines
    for the majority of C's history. Even if you omit `long long'
    (and under your scheme of things it might never have come to pass),
    you're still talking about four distinct widths when most machines
    supported three or even just two. Would C have gained enough of
    a foothold that you would care about it today? Hard to say.

    > Given that I know my target hardware has an 8-bit byte size and natural word
    > size of 32-bits, what int prefixes do I use to span the range 16, 32 and
    > 64-bits? And perhaps stay the same when compiled for 64-bit target?


    You're assuming more "givens" than C does (or, as I argue
    above, could), but the <stdint.h> types seem a reasonable choice.

    > Is there any danger of long long int ending up as 128-bits? Sometimes I
    > might need 64-bits but don't want the overheads of 128.


    Yes, of course there's such a "danger." But I've got to raise
    an eyebrow at your attitude toward the possibility that your hardware
    might grow more capable: It's a danger if your computer gets bigger?
    Have you been reading "The Forbin Project" or something?

    Oh, and what are these "overheads" of which you speak? Can
    you quantify them?

    > Or should I just give up and use int32_t and so on, and hope these are
    > implemented in the compiler?


    Use fixed-width or least-width types if you *need* them.
    Otherwise, make your type choice based on range and convenience.
    The <limits.h> header can be your friend.

    > (Haven't seen anything similar for floating point in my C99 draft, but it
    > seems better behaved, except for long double which gives results of 96 or
    > 128 below (neither of which match the 80-bits of my cpu).)


    "Ayeh," as they say Down East when a citified vacationer
    says something silly. Here's a project for you: Get the source
    of gcc and modify it to use a ten-byte `long double'. (This will
    involve a fair amount of work, but not an enormous amount: gcc
    is reputed to be pretty freely retargetable.) Find some code
    that uses `long double' heavily, and compile it with both the
    modified gcc and a "stock" version. Measure the performance of
    the two resulting programs. Discuss.

    [Code snipped; see vippstar's response. I'll add that I have
    used a machine on which the code would have reported "0 bits"
    for all the sizes it computes.]

    --
    Eric Sosman, Jan 9, 2008
    #5
  6. In article <>,
    user923005 <> wrote:

    >Your method is not accurate. It is possible to have trap bits or


    Wouldn't that be "trap values" rather than "trap bits" ?

    On the other hand, I was scanning through the trap value / padding
    bits in C99 the other day, and noticed that the state of padding
    bits is not allowed to affect whether a particular value is a trap
    value or not, so if there did happen to be a bit which when set (or
    clear) triggered a trap, it would officially have to be one
    of the "value bits", leading to a rather large number of
    "trap values"!

    >unused bits (e.g. IBM 360 had 32 bits but only used 24 bits for some
    >types). There are also bits to represent NAN and INF for the floating
    >point, and the amount of bits dedicated to mantissa and exponent can
    >differ even for a data type with the same physical width in bits (e.g.
    >DFLOAT and GFLOAT on OpenVMS).


    Though if the floating point representation follows C99 Appendix F
    and defines __STDC_IEC_559__ then it cannot have seperate bits
    for NaN or Inf as those are keyed in IEC 559 with special exponents.
    --
    "Is there any thing whereof it may be said, See, this is new? It hath
    been already of old time, which was before us." -- Ecclesiastes
    Walter Roberson, Jan 9, 2008
    #6
  7. Bart C

    CBFalconer Guest

    Bart C wrote:
    >

    .... snip ...
    >
    > Integer widths that obey the rule short < int < long int <long
    > long int (instead of short<=int<=long int or whatever) would be
    > far more intuitive and much more useful (as it is now, changing
    > int x to long int x is not guaranteed to change anything, so is
    > pointless)
    >
    > Given that I know my target hardware has an 8-bit byte size and
    > natural word size of 32-bits, what int prefixes do I use to span
    > the range 16, 32 and 64-bits? And perhaps stay the same when
    > compiled for 64-bit target?


    All you need to know is the minimum guaranteed sizes for the
    standard types. They are:

    char 8 bits
    short 16 bits
    int 16 bits
    long 32 bits
    long long 64 bits

    Simply pick a type that is large enough for your operations (or the
    unsigned equivalent). If you wish you can use the values in
    <limits.h> to check the numerical limits. Unsigned types have a
    min value of 0. See section 5.2.4.2.1 Sizes of integer types
    <limits.h> in the C standard.

    --
    Chuck F (cbfalconer at maineline dot net)
    <http://cbfalconer.home.att.net>
    Try the download section.



    --
    Posted via a free Usenet account from http://www.teranews.com
    CBFalconer, Jan 9, 2008
    #7
  8. Bart C

    Guest

    Bart C wrote:
    > I've always had a problem knowing exactly how wide my integer variables were
    > in C, and the little program below has increased my confusion.
    >
    > Run on 3 compilers on the same cpu (32-bit pentium), sometimes int and long
    > int are the same, and long long int is twice the width; or sometimes both
    > long int and long long int are twice the width of int.
    >
    > This apparently all quite normal according to my c99 draft and c-faq.com.
    > However it doesn't alter the fact that this is all very 'woolly' and
    > ambiguous.


    It's meant to be lose, to allow efficient implementation of C on a
    wide variety of platforms. It's precisely because of the looseness of
    C's definitions of such things that C is currently one of the most
    widely implemented computer languages.

    > Integer widths that obey the rule short < int < long int <long long int
    > (instead of short<=int<=long int or whatever) would be far more intuitive
    > and much more useful (as it is now, changing int x to long int x is not
    > guaranteed to change anything, so is pointless)


    The actual requirements are not in terms of widths. The actual
    requirements are stated in terms of the range of values that can be
    represented by a given type. That range for any given integer type
    must be a sub-range of the range that can be represented by any
    integer type with the same signedness and higher rank. While perverse
    and extremely unlikely, it's permitted for a conforming implementation
    to have sizeof(long long) < sizeof(short), as long as LLONG_MAX >=
    SHORT_MAX, and LLONG_MIN <= SHORT_MIN. This would imply that 'short'
    has padding bits.

    > Given that I know my target hardware has an 8-bit byte size and natural word
    > size of 32-bits, what int prefixes do I use to span the range 16, 32 and
    > 64-bits?


    int_fast16_t, int_fast32_t, and int_fast64_t.

    > ... And perhaps stay the same when compiled for 64-bit target?


    There's no portable way to guarantee that. If a non-portable way is
    acceptable, then read the implementation's documentation.

    > Is there any danger of long long int ending up as 128-bits? ...


    Yes.

    > ...Sometimes I might need 64-bits but don't want the overheads of 128.


    That's what int_fast64_t was invented for.

    > Or should I just give up and use int32_t and so on, and hope these are
    > implemented in the compiler?


    As you describe it, you don't seem to need exact-sized types. The fast-
    sized types are more appropriate in this case (as they are in most
    cases that don't involve binary compatibility), unless space is more
    important to you than speed, in which case you should use the least-
    sized types. Both the fast-sized and least-sized types have the
    advantage of being mandatory for n=8,16,32, and 64, for conforming
    implementations of C99.

    > (Haven't seen anything similar for floating point in my C99 draft, but it
    > seems better behaved, except for long double which gives results of 96 or
    > 128 below (neither of which match the 80-bits of my cpu).)


    C99 doesn't mandate any stricter requirements on the size of floating
    point types than it does for the integer types. Conversions from float
    to double, or from double to long double, must be exact, with all that
    implies for the range of precision of each of those types. However, a
    conforming implementation of C could still have sizeof(long double) <
    sizeof(float).

    Exception: if __STDC_IEC_559__ is predefined by the implementation,
    then the standard imposes much stricter requirements on floating point
    types. In that case (Annex F, F2p1):

    -- The float type matches the IEC 60559 single format.
    -- The double type matches the IEC 60559 double format.
    -- The long double type matches an IEC 60559 extended format,307) else
    a
    non-IEC 60559 extended format, else the IEC 60559 double format.
    Any non-IEC 60559 extended format used for the long double type shall
    have more
    precision than IEC 60559 double and at least the range of IEC 60559
    double.30
    , Jan 9, 2008
    #8
  9. wrote:
    <snip>
    > 'sizeof (type) * CHAR_BIT' is not an accurate way to calculate the
    > number of bits 'type' uses in your system.


    Unless (type) is an unsigned integral, and the environment is C99-compliant
    in this respect (as are most general computing environments, i.e.
    non-embedded renditions of Windows and Unix).

    C99 also solved the memset(p, 0, sizeof *p) issue, so one needn't always use
    object initializers to properly "zero" automatic and dynamic structures when
    the members are just unsigned integrals and pointers.

    I could be wrong, but, IIRC, this was the ultimate and intended outcome of
    some of the finer definitions in C99.

    This is yet another darned good reason for using unsigned integrals
    everywhere unless you have cause for not doing so. It rids you of
    unnecessary "cognitive load" that lurking in comp.lang.c too long (but not
    long enough) will curse you with ;)
    William Ahern, Jan 9, 2008
    #9
  10. In article <f51g55-nac.ln1@wilbur.25thandClement.com>,
    William Ahern <william@wilbur.25thandClement.com> wrote:
    > wrote:
    ><snip>
    >> 'sizeof (type) * CHAR_BIT' is not an accurate way to calculate the
    >> number of bits 'type' uses in your system.


    >Unless (type) is an unsigned integral, and the environment is C99-compliant
    >in this respect


    Hmmm?

    According to N794,

    6.1.2.8.2 Integer types

    For unsigned integer types other than unsigned char,
    the bits of the object representation shall be divided into
    two groups: value bits and paddiing bits (there need not be
    any of the latter). [...]

    For signed integer types, the bits of the object
    representation shall be divided into three groups: value
    bits, padding bits, and the sign bit. There need not be any
    padding bits; there shall be exactly one sign bit. Each bit
    that is a value bit shall have the same value as the
    same bit in the object representation of the corresponding
    unsigned type (if there are M value bits in the signed type
    and N in the unsigned type, then M<N). [...]


    Thus the impossibility of padding bits applies only to
    unsigned char, not to unsigned integral types in general.
    --
    So you found your solution
    What will be your last contribution?
    -- Supertramp (Fool's Overture)
    Walter Roberson, Jan 9, 2008
    #10
  11. In article <fm3j0b$gso$>,
    Walter Roberson <-cnrc.gc.ca> wrote:
    >In article <>,
    >user923005 <> wrote:


    >>Your method is not accurate. It is possible to have trap bits or


    >Wouldn't that be "trap values" rather than "trap bits" ?


    >On the other hand, I was scanning through the trap value / padding
    >bits in C99 the other day, and noticed that the state of padding
    >bits is not allowed to affect whether a particular value is a trap
    >value or not, so if there did happen to be a bit which when set (or
    >clear) triggered a trap, it would officially have to be one
    >of the "value bits", leading to a rather large number of
    >"trap values"!


    I misremembered. N794 6.1.2.8.2 Integer types

    {footnote} [39] Some combinations of padding bits might
    generate trap representations, for example, if one padding
    bit is a parity bit. Regardless, no arithmetic operation
    on valid values can generate a trap representation other
    than as part of an exception such as overflow, and this
    cannot occur with unsigned types. All other combinations
    of padding bits are alternative object representations of
    the value specified by the value bits.
    --
    "History is a pile of debris" -- Laurie Anderson
    Walter Roberson, Jan 9, 2008
    #11
  12. Bart C

    CBFalconer Guest

    Walter Roberson wrote:
    >

    .... snip ...
    >
    > I misremembered. N794 6.1.2.8.2 Integer types


    I suggest you update your standard copy to at least N869, which was
    the last draft before issuing C99. It is also the last to have a
    text version. You can get a copy, diddled for easy searching and
    quotation, as N869_txt.bz2, which is bzip2 compressed, at:

    <http://cbfalconer.home.att.net/download/>

    --
    Chuck F (cbfalconer at maineline dot net)
    <http://cbfalconer.home.att.net>
    Try the download section.


    --
    Posted via a free Usenet account from http://www.teranews.com
    CBFalconer, Jan 10, 2008
    #12
  13. Bart C

    Bart C Guest

    Flash Gordon wrote:
    > Bart C wrote, On 09/01/08 20:33:


    >> Integer widths that obey the rule short < int < long int <long long
    >> int (instead of short<=int<=long int or whatever) would be far more
    >> intuitive and much more useful (as it is now, changing int x to long
    >> int x is not guaranteed to change anything, so is pointless)

    >
    > Now look at a 32 bit DSP which cannot deal with anything below 32
    > bits. Given your definition it would have to do at least
    > sizeof(char) == 1 - 32 bits
    > sizeof(short) == 2 - 64 bits
    > sizeof(int) == 3 - 96 bits
    > sizeof(long) == 4 - 128 bits
    > sizeof(long long) == 5 - 156 bits [160?]


    Yes in this example it sort of makes sense, if the compiler does not try too
    hard to impose anything else.

    However it's not impossible either for the compiler to impose 8, 16, 32,
    64-bit word sizes (don't know how capable DSPs are or whether this is even
    desirable). So a 128K array of 8-bit data for example could take 128KB
    instead of 512KB.

    > If those are your minimum requirements then you use
    > char - at least 8 bits
    > short - at least 16 bits
    > int - at least 16 bits (but likely to be larger)
    > long - at least 32 bits
    > long long - at least 64 bits


    At first this seems the way to go: char, short, long, long long giving at
    least 8, 16, 32, 64-bits respectively.
    Except my test showed the long int was 32-bits on one compiler and 64-bits
    in another -- for the same processor. This just seems plain wrong.

    It means my program that needs 32-bit data runs happily using long int under
    dev-cpp, but takes maybe twice as long under gcc because long int now takes
    twice the memory and the processor unnecessarily emulates 64-bit arithmetic.

    > Alternatively, use the types defined in stdint.h (or inttypes.h) which
    > have been added in C99. These headers provide you exact width types


    OK looks like this is what I will have to do.

    wrote:
    >> printf("LD = %3d bits\n",sizeof(ld)*CHAR_BIT);

    > The proper format specifier for size_t is '%zu'


    I would never have guessed! Although the results (on one rerun anyway) were
    the same.

    Thanks for all the replies.

    Bart
    Bart C, Jan 10, 2008
    #13
  14. Bart C

    Bart C Guest

    CBFalconer wrote:
    > Bart C wrote:


    >> Given that I know my target hardware has an 8-bit byte size and
    >> natural word size of 32-bits, what int prefixes do I use to span
    >> the range 16, 32 and 64-bits? And perhaps stay the same when
    >> compiled for 64-bit target?

    >
    > All you need to know is the minimum guaranteed sizes for the
    > standard types. They are:
    >
    > char 8 bits
    > short 16 bits
    > int 16 bits
    > long 32 bits
    > long long 64 bits


    This is an example of a problem I anticipate:

    long ftell( FILE *stream );

    The above is from documentation for a function in a dynamic library.
    Probably the 'long' means a 32-bit value (this is on a MS platform). But for
    my compiler 'long' might be implemented as 64-bits. What happens?
    (Especially if long applied to a parameter rather than the return value.)

    Bart
    Bart C, Jan 10, 2008
    #14
  15. Bart C

    Jack Klein Guest

    On Thu, 10 Jan 2008 01:27:48 GMT, "Bart C" <> wrote in
    comp.lang.c:

    > CBFalconer wrote:
    > > Bart C wrote:

    >
    > >> Given that I know my target hardware has an 8-bit byte size and
    > >> natural word size of 32-bits, what int prefixes do I use to span
    > >> the range 16, 32 and 64-bits? And perhaps stay the same when
    > >> compiled for 64-bit target?

    > >
    > > All you need to know is the minimum guaranteed sizes for the
    > > standard types. They are:
    > >
    > > char 8 bits
    > > short 16 bits
    > > int 16 bits
    > > long 32 bits
    > > long long 64 bits

    >
    > This is an example of a problem I anticipate:
    >
    > long ftell( FILE *stream );
    >
    > The above is from documentation for a function in a dynamic library.
    > Probably the 'long' means a 32-bit value (this is on a MS platform). But for
    > my compiler 'long' might be implemented as 64-bits. What happens?
    > (Especially if long applied to a parameter rather than the return value.)


    The above prototype is for a standard C library function. Whatever
    "dynamic" means is not a language issue.

    If the library is supplied with your platform, either your compiler
    claims to be compatible with the platform or it does not. If it does,
    and the size of its long type is different from that of the platform's
    library, then you implementation must provide its own alternative to
    the library function, or perhaps provide a wrapper around the
    platform's functions as needed, converting between its data types and
    those of the underlying system.

    A compiler with a 64-bit long is not going to claim Win32
    compatibility.

    Simple.

    I think you are looking for problems that you are not likely to run
    int.

    When you develop a program for a platform, you will use a compiler for
    that platform. If you want to add a third party library, you will use
    one that is built for that compiler and platform combination.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://c-faq.com/
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
    Jack Klein, Jan 10, 2008
    #15
  16. Bart C

    Flash Gordon Guest

    Bart C wrote, On 10/01/08 01:16:
    > Flash Gordon wrote:
    >> Bart C wrote, On 09/01/08 20:33:

    >
    >>> Integer widths that obey the rule short < int < long int <long long
    >>> int (instead of short<=int<=long int or whatever) would be far more
    >>> intuitive and much more useful (as it is now, changing int x to long
    >>> int x is not guaranteed to change anything, so is pointless)

    >> Now look at a 32 bit DSP which cannot deal with anything below 32
    >> bits. Given your definition it would have to do at least
    >> sizeof(char) == 1 - 32 bits
    >> sizeof(short) == 2 - 64 bits
    >> sizeof(int) == 3 - 96 bits
    >> sizeof(long) == 4 - 128 bits
    >> sizeof(long long) == 5 - 156 bits [160?]

    >
    > Yes in this example it sort of makes sense, if the compiler does not try too
    > hard to impose anything else.
    >
    > However it's not impossible either for the compiler to impose 8, 16, 32,
    > 64-bit word sizes (don't know how capable DSPs are or whether this is even
    > desirable). So a 128K array of 8-bit data for example could take 128KB
    > instead of 512KB.


    It is not impossible, but on a significant number of main stream DSP
    processors using anything less than the size the processor understands
    (16 bits, 24 bits, 32 bits and 48 being common) you would make the
    smaller types very inefficient since it would have to keep masking etc.
    So to write an 8 bit char to memory it would have to on one of the
    processors...
    shift accumulator left 16 bits (1 clock)
    load memory location shifting data left 8 bits (1 clock)
    save shifting right 8 bits (1 clock)
    So you have turned a common 1 clock cycle operation in to a 4 clock
    cycles which also change the contents of the accumulator. Do you really
    think a 400% increase in the time to save a char is worth the cost?

    A lot of other operations would also be slowed down.

    On such processors it really does not make sense to use smaller data
    types than the processor understands so why introduce the additional
    complexity to the compiler just to make it extremely inefficient if some
    code does use a short or a char?

    >> If those are your minimum requirements then you use
    >> char - at least 8 bits
    >> short - at least 16 bits
    >> int - at least 16 bits (but likely to be larger)
    >> long - at least 32 bits
    >> long long - at least 64 bits

    >
    > At first this seems the way to go: char, short, long, long long giving at
    > least 8, 16, 32, 64-bits respectively.
    > Except my test showed the long int was 32-bits on one compiler and 64-bits
    > in another -- for the same processor. This just seems plain wrong.


    No, it is NOT wrong. At least, not necessarily. If one implementation
    supports things which require a 64 bit integer type to perform certain
    operations (e.g. supporting fseek on large files) then selecting a 64
    bit long makes perfect sense. Another implementation might have decided
    that supporting legacy broken code that assumes int and long are the
    same is more important. These are both valid trade-offs.

    > It means my program that needs 32-bit data runs happily using long int under
    > dev-cpp, but takes maybe twice as long under gcc because long int now takes
    > twice the memory and the processor unnecessarily emulates 64-bit arithmetic.


    Hmm. Did you realise that you are saying that gcc produces code that
    uses twice the memory of gcc? dev-cpp uses either gcc, the MinGW port of
    gcc or the Cygwin port of gcc as the compiler.

    >> Alternatively, use the types defined in stdint.h (or inttypes.h) which
    >> have been added in C99. These headers provide you exact width types

    >
    > OK looks like this is what I will have to do.


    Using the fast types would make more sense than the fixed width ones
    unless you *really* need fixed-width types (most people don't, although
    I do) or to save memory (in which case the least types maximise
    portability).

    > wrote:
    >>> printf("LD = %3d bits\n",sizeof(ld)*CHAR_BIT);

    >> The proper format specifier for size_t is '%zu'

    >
    > I would never have guessed! Although the results (on one rerun anyway) were
    > the same.


    Undefined behaviour is like that. It can hide itself by doing exactly
    what you expect, or it can cause your computer to come alive and eat all
    the food in your fridge.
    --
    Flash Gordon
    Flash Gordon, Jan 10, 2008
    #16
  17. Bart C

    James Kuyper Guest

    Flash Gordon wrote:
    > Bart C wrote, On 10/01/08 01:16:
    >> Flash Gordon wrote:
    >>> Bart C wrote, On 09/01/08 20:33:

    >>
    >>>> Integer widths that obey the rule short < int < long int <long long
    >>>> int (instead of short<=int<=long int or whatever) would be far more
    >>>> intuitive and much more useful (as it is now, changing int x to long
    >>>> int x is not guaranteed to change anything, so is pointless)
    >>> Now look at a 32 bit DSP which cannot deal with anything below 32
    >>> bits. Given your definition it would have to do at least
    >>> sizeof(char) == 1 - 32 bits
    >>> sizeof(short) == 2 - 64 bits
    >>> sizeof(int) == 3 - 96 bits
    >>> sizeof(long) == 4 - 128 bits
    >>> sizeof(long long) == 5 - 156 bits [160?]

    >>
    >> Yes in this example it sort of makes sense, if the compiler does not
    >> try too hard to impose anything else.
    >>
    >> However it's not impossible either for the compiler to impose 8, 16,
    >> 32, 64-bit word sizes (don't know how capable DSPs are or whether this
    >> is even desirable). So a 128K array of 8-bit data for example could
    >> take 128KB instead of 512KB.

    >
    > It is not impossible, but on a significant number of main stream DSP
    > processors using anything less than the size the processor understands
    > (16 bits, 24 bits, 32 bits and 48 being common) you would make the
    > smaller types very inefficient since it would have to keep masking etc.


    On any given processor, types that are too small are inefficient because
    they must be emulated by bit-masking operations, while types that are
    two big are inefficient because they must be emulated using multiple
    instances of the largest efficient type. If signed char, short, int,
    long and long long were all required to have different sizes, a
    processor with hardware support for fewer than 5 different sizes would
    have to choose one form of inefficiency or the other; efficient
    implementation of all 5 types would not be an option.

    In practice, what would be provided would depend upon what's needed, and
    not just what's efficient. There's a lot more need for 8 or 16 bit types
    than there is for 128 or 156 bit types (though I'm not saying there's no
    need for those larger types - I gather that the cryptographic community
    loves them).
    James Kuyper, Jan 10, 2008
    #17
  18. Bart C

    Bart C Guest

    Flash Gordon wrote:
    > Bart C wrote, On 10/01/08 01:16:


    >> It means my program that needs 32-bit data runs happily using long
    >> int under dev-cpp, but takes maybe twice as long under gcc because
    >> long int now takes twice the memory and the processor unnecessarily
    >> emulates 64-bit arithmetic.

    >
    > Hmm. Did you realise that you are saying that gcc produces code that
    > uses twice the memory of gcc? dev-cpp uses either gcc, the MinGW port
    > of gcc or the Cygwin port of gcc as the compiler.


    Well, dev-cpp under winxp reported 32 bits for long int; gcc under linux
    reported 64 bits for long int, both on same pentium machine. So, yes, I
    guess I'm saying a huge array of long ints would be take double the memory
    in gcc in this case. Maybe these are all configurable options but I'm using
    them 'out-of-the-box'.

    Other points well explained and understood.

    --
    Bart
    Bart C, Jan 10, 2008
    #18
  19. Bart C

    Bart C Guest

    Jack Klein wrote:
    > On Thu, 10 Jan 2008 01:27:48 GMT, "Bart C" <> wrote in
    > comp.lang.c:


    >>> Bart C wrote:


    >> This is an example of a problem I anticipate:
    >>
    >> long ftell( FILE *stream );
    >>
    >> The above is from documentation for a function in a dynamic library.
    >> Probably the 'long' means a 32-bit value (this is on a MS platform).
    >> But for my compiler 'long' might be implemented as 64-bits. What
    >> happens? (Especially if long applied to a parameter rather than the
    >> return value.)

    >
    > The above prototype is for a standard C library function. Whatever
    > "dynamic" means is not a language issue.


    It means the function could have been compiled with a different C compiler
    (maybe even a different language) with a specification published using the
    local semantics (in this case the exact meaning of 'long').

    I had in mind dynamic linking but I think the problem can occur with static
    linking too, if using object files compiled elsewhere. (You will say some of
    these terms are not in the C standard but this is a practical problem.)

    > If the library is supplied with your platform, either your compiler
    > claims to be compatible with the platform or it does not. If it does,
    > and the size of its long type is different from that of the platform's
    > library, then you implementation must provide its own alternative to
    > the library function, or perhaps provide a wrapper around the
    > platform's functions as needed, converting between its data types and
    > those of the underlying system.


    > When you develop a program for a platform, you will use a compiler for
    > that platform. If you want to add a third party library, you will use
    > one that is built for that compiler and platform combination.


    Provided a binary library is for the correct platform (object format,
    processor and so on), surely I can use any C compiler to compile the header
    files? Otherwise it seems overly restrictive.

    The one overriding theme in this newsgroup seems to be that of portability,
    yet if I distribute a library I need to specify a particular compiler or
    supply a version for every possible compiler?

    Wouldn't it be better, in published header files, to use more specific type
    designators than simply 'long' (since, once compiled, the binary will not
    change). Then a compiler can use common sense out in dealing with it. (Since
    the processor is the same there will surely be a local word size that will
    match.)

    Bart

    [oops, originally sent to your email instead of group]
    Bart C, Jan 10, 2008
    #19
  20. Bart C

    Flash Gordon Guest

    Bart C wrote, On 10/01/08 12:20:
    > Flash Gordon wrote:
    >> Bart C wrote, On 10/01/08 01:16:

    >
    >>> It means my program that needs 32-bit data runs happily using long
    >>> int under dev-cpp, but takes maybe twice as long under gcc because
    >>> long int now takes twice the memory and the processor unnecessarily
    >>> emulates 64-bit arithmetic.

    >> Hmm. Did you realise that you are saying that gcc produces code that
    >> uses twice the memory of gcc? dev-cpp uses either gcc, the MinGW port
    >> of gcc or the Cygwin port of gcc as the compiler.

    >
    > Well, dev-cpp under winxp reported 32 bits for long int; gcc under linux
    > reported 64 bits for long int, both on same pentium machine. So, yes, I
    > guess I'm saying a huge array of long ints would be take double the memory
    > in gcc in this case.


    You completely missed the point. You are comparing gcc against gcc.
    dev-cpp has NOTHING to do with it. You are either comparing the MinGW
    implementation of gcc (which has to match the MS C library) with one of
    the Linux implementations of gcc (which has to match the glibc version)
    or you are comparing the Cygwin version of gcc against one of the Linux
    implementations.

    I also strongly suspect that you are comparing an implementation
    designed for a 32 bit processor against one designed for a 64 bit
    processor (i.e. the 64 bit version of Linux). Did you expect that WinXP
    would magically become a 64 bit OS just because you ran it on a 64 bit
    processor?

    > Maybe these are all configurable options but I'm using
    > them 'out-of-the-box'.


    They have to match the library, and gcc does not come with a library, it
    just uses the one provided by the system. I suspect that the
    "out-of-the-box' for dev-cpp is to use MinGW on Linux rather than
    Cygwin, but I don't think that would make any difference in this case.
    --
    Flash Gordon
    Flash Gordon, Jan 10, 2008
    #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. Matt
    Replies:
    88
    Views:
    1,347
    jacob navia
    Apr 16, 2004
  2. George Marsaglia

    Assigning unsigned long to unsigned long long

    George Marsaglia, Jul 8, 2003, in forum: C Programming
    Replies:
    1
    Views:
    672
    Eric Sosman
    Jul 8, 2003
  3. Matt
    Replies:
    106
    Views:
    1,869
    Dan Pop
    Apr 19, 2004
  4. Daniel Rudy

    unsigned long long int to long double

    Daniel Rudy, Sep 19, 2005, in forum: C Programming
    Replies:
    5
    Views:
    1,184
    Peter Shaggy Haywood
    Sep 20, 2005
  5. Mathieu Dutour

    long long and long

    Mathieu Dutour, Jul 17, 2007, in forum: C Programming
    Replies:
    4
    Views:
    471
    santosh
    Jul 24, 2007
Loading...

Share This Page