Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Use of Long and Long Long (http://www.velocityreviews.com/forums/t583507-use-of-long-and-long-long.html)

Bart C 01-09-2008 08:33 PM

Use of Long and Long Long
 
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);

}





vippstar@gmail.com 01-09-2008 09:03 PM

Re: Use of Long and Long Long
 
On Jan 9, 10:33 pm, "Bart C" <b...@freeuk.com> 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.

Flash Gordon 01-09-2008 10:08 PM

Re: Use of Long and Long Long
 
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

user923005 01-09-2008 10:31 PM

Re: Use of Long and Long Long
 
On Jan 9, 12:33*pm, "Bart C" <b...@freeuk.com> 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>

Eric Sosman 01-09-2008 10:39 PM

Re: Use of Long and Long Long
 
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@sun.com

Walter Roberson 01-09-2008 10:48 PM

Re: Use of Long and Long Long
 
In article <5f3da179-7ad2-43c3-9275-8061e2645cb1@c4g2000hsg.googlegroups.com>,
user923005 <dcorbit@connx.com> 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

CBFalconer 01-09-2008 11:08 PM

Re: Use of Long and Long Long
 
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


jameskuyper@verizon.net 01-09-2008 11:09 PM

Re: Use of Long and Long Long
 
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

William Ahern 01-09-2008 11:15 PM

Re: Use of Long and Long Long
 
vippstar@gmail.com 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 ;)


Walter Roberson 01-09-2008 11:43 PM

Re: Use of Long and Long Long
 
In article <f51g55-nac.ln1@wilbur.25thandClement.com>,
William Ahern <william@wilbur.25thandClement.com> wrote:
>vippstar@gmail.com 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)


All times are GMT. The time now is 06:15 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.