By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,453 Members | 3,225 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,453 IT Pros & Developers. It's quick & easy.

Use of Long and Long Long

P: n/a
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);

}


Jan 9 '08 #1
Share this Question
Share on Google+
21 Replies


P: n/a
On Jan 9, 10:33 pm, "Bart C" <b...@freeuk.comwrote:
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.hand (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 '08 #2

P: n/a
On Jan 9, 12:33*pm, "Bart C" <b...@freeuk.comwrote:
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>
Jan 9 '08 #3

P: n/a
In article <5f**********************************@c4g2000hsg.g ooglegroups.com>,
user923005 <dc*****@connx.comwrote:
>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
Jan 9 '08 #4

P: n/a
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
Jan 9 '08 #5

P: n/a
vi******@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 ;)

Jan 9 '08 #6

P: n/a
In article <f5************@wilbur.25thandClement.com>,
William Ahern <wi*****@wilbur.25thandClement.comwrote:
>vi******@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)
Jan 9 '08 #7

P: n/a
In article <fm**********@canopus.cc.umanitoba.ca>,
Walter Roberson <ro******@ibd.nrc-cnrc.gc.cawrote:
>In article <5f**********************************@c4g2000hsg.g ooglegroups.com>,
user923005 <dc*****@connx.comwrote:
>>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
Jan 9 '08 #8

P: n/a
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.hto check the numerical limits. Unsigned types have a
min value of 0. See section 5.2.4.2.1 Sizes of integer types
<limits.hin 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

Jan 10 '08 #9

P: n/a
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

Jan 10 '08 #10

P: n/a
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.

vi******@gmail.com 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
Jan 10 '08 #11

P: n/a
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).
Jan 10 '08 #12

P: n/a
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

Jan 10 '08 #13

P: n/a
Bart C wrote:
Jack Klein wrote:
....
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.)
An implementation of C includes not only the compiler but the standard
library and the linker, even if those parts did not all come from the
same vendor. If two different compilers have different sizes for the
same type, and that type is used as an argument to or return value from
the C standard library, then the two compilers are generating code that
must be linked with different versions of the C standard library. If the
compiler automatically invokes the linker (as is the case with most of
the compilers I'm familiar with), it's the compiler's responsibility to
automatically link to the correct version of the standard library.
>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,
Note: a single platform can support many different object formats; the
one I use most often supports at least four different formats, possibly
more.
processor and so on), surely I can use any C compiler to compile the header
files? Otherwise it seems overly restrictive.
The C standard makes no such guarantees. Even using a single compiler,
it's possible to compile code modules that can't be linked together. The
compiler I use most often supports 3 different ABIs (I don't remember
what ABI is an acronym for, but it corresponds to having different sizes
for various types, and possibly different function call protocols). It
supports one 64-bit ABI, and two mutually incompatible 32-bit ABIs, and
you can't link code compiled for one ABI with code compiled for another
ABI. However, you can run programs built with different ABIs at the same
time in the same shell.
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?
If you distribute your library as compilable source code, and if you can
write that source code using strictly portable constructs, you only need
to produce one version for all conforming compilers. If you distribute
it as an object library, you're going to have to create a separate
library for each supported object code format, and you'll have to decide
which formats to support.
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
For the libraries I use most often, the installation script uses various
sophisticated techniques to determine the characteristics of the
compiler it's installed with, and it creates header files that set up
typedefs for the library's interfaces. Code which uses that library must
be compiled using a compiler compatible with the one used during
installation of the library, but the user code just uses the typedef,
and doesn't need to be aware of the fact that it's a different type when
using different compilers.
Jan 10 '08 #14

P: n/a
Bart C wrote:
[...]
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.
No, because implementation-provided headers may (often do)
contain implementation-specific "magic."

/* <setjmp.hfor Frobozz Magic C */
typedef _registerblock jmp_buf[1];
_restrictedvalue int setjmp(jmp_buf);
_nonreturning void longjmp(jmp_buf, int);

Compile this header with a non-Frobozz compiler, and it's quite
likely not to recognize the three special tokens. (If you are
particularly unlucky, it *will* recognize them ...)

--
Eric Sosman
es*****@ieee-dot-org.invalid
Jan 10 '08 #15

P: n/a
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
Jan 10 '08 #16

P: n/a
James Kuyper wrote, On 10/01/08 12:14:
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.
On these processors it does not make sense to do the work to provide
smaller types as they would not be used because of the nature of what
the processors are used for and the consequent inefficiencies, and it
would not make sense for int to by larger than one C byte because that
would make using int impracticable for most purposes and prevent you
from reusing source code not specifically targeted at the processor
without changing all the int and unsigned int variables to signed and
unsigned char. Thus C would be very difficult to use on those processors.
In practice, what would be provided would depend upon what's needed, and
not just what's efficient.
Yes, and in practice that means making char, short and int all the same
size, that being 16, 24, 32 or 48 bits depending on what the processor
supports.
There's a lot more need for 8 or 16 bit types
Not on the processors I'm talking about or the purposes they are used
for. The reason they do not have the concept of types that small is that
they are designed for applications which only require larger types and
require the maximum speed available from them. If smaller types were
required the processors would not sell.
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).
Not only there I believe, but the world is a *lot* larger than desktop
applications. Certainly on the types of image and video processing I've
done I would have been more likely to use larger types than smaller
types, although I did my best to stick to the natural size of the
processors and hence used int a lot.
--
Flash Gordon
Jan 10 '08 #17

P: n/a
In article <8gphj.5611$sH.531@trnddc04>,
James Kuyper <ja*********@verizon.netwrote:
>(I don't remember
what ABI is an acronym for, but it corresponds to having different sizes
for various types, and possibly different function call protocols)
It's "Application Binary Interface". Contrast with "API", where "P"
stands "Programming", which is typically a source-level specification.

-- Richard
--
:wq
Jan 10 '08 #18

P: n/a
vi******@gmail.com writes:
On Jan 9, 10:33 pm, "Bart C" <b...@freeuk.comwrote:
>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.hand (u)intN_t where N is 8,16,32,64. You may
find that does not guarantee much either.
What the standard does guarantee is certain minimum *ranges* for the
predefined integer types. Specifically:

signed char is at least -127 .. +127
unsigned char is at least 0 .. 255
char is the same as either signed char or unsigned char

short is at least -32767 .. +32767
unsigned short is at least 0 .. 65535

int and unsigned int have the same minimal ranges as short and
unsigned short

long is at least -2**31 .. +2*31
unsigned long is at least 0 .. 2**32-1

long long is at least -2**63 .. +2**63
unsigned long long is at least 0 .. 2**64-1

(In the following, "<=" means that the range of the second
type includes the range of the first type.)

signed char <= short <= int <= long <= long long

unsigned char <= unsigned short <= unsigned int <= unsigned long
<= unsigned long long

This implies a minimum number of bits for each type (there have to be
enough bits to represent each distinct value in the range).

The reason most of these guarantees don't apply to sizeof(whatever) is
that a type can have padding bits which don't contribute to the value.
The vast majority of implementations you're likely to run into will
have no padding bits but you shouldn't assume that there are none
(unless the assumption makes your task significantly easier *and*
you're willing to give up some degree of portability).

[...]
The proper format specifier for size_t is '%zu'
But a significant number of implementations still don't support "%zu".
You can also cast to unsigned long and use "%lu" (this can fail if
size_t is wider than unsigned long *and* the value you're printing
happens to exceed ULONG_MAX).
'sizeof (type) * CHAR_BIT' is not an accurate way to calculate the
number of bits 'type' uses in your system.
It is *if* you can assume there are no padding bits (see above). But
it is an accurate way to calculate the number of types 'type' will
*occupy*.

--
Keith Thompson (The_Other_Keith) <ks***@mib.org>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jan 10 '08 #19

P: n/a
Bart C wrote:
I've always had a problem knowing exactly how wide my integer
variables were in C...
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...
Just been looking at a book on the C# language and it has these signed
datatypes:

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

With unsigned versions byte, ushort, uint, ulong. Perfect and unambiguous,
exactly what I wanted in C. By comparison C's numeric types are a minefield.
(And visually untidy, like _Bool and size_t)

Of course C# is a fairly recent language devised by MS that didn't have to
worry about old code or running on obscure processors.

Is there anywhere a development of C that has been brought up-to-date and
tidied up, to run on modern 32/64-bit CPUs (with a stack of course :-)?
Bart

Jan 15 '08 #20

P: n/a
Bart C <bc@freeuk.comwrote:
Bart C wrote:
I've always had a problem knowing exactly how wide my integer
variables were in C...
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...
Just been looking at a book on the C# language and it has these signed
datatypes:

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

With unsigned versions byte, ushort, uint, ulong. Perfect and unambiguous,
exactly what I wanted in C. By comparison C's numeric types are a minefield.
(And visually untidy, like _Bool and size_t)

Of course C# is a fairly recent language devised by MS that didn't have to
worry about old code or running on obscure processors.
Or worry about new code, either. In some respects all that mattered was the
instant impressions and opinions at the moment of inception. Only time can
tell whether they're "perfect and unamgiguous" over a longer duration of
computing evolution. Same thing happened with UCS-2/UTF-16. I highly doubt
that C# "got it right".

Only a few years out and C# has already become disheveled. Delegates weren't
the panacea once touted (maybe not be the creators). There are many other
warts and such popping up, especially in relation to newer and more modern
languages.

Many (most?) will argue that C's path is, on balance, preferable. A little
"ambiguity" never hurt anybody. Certainly it forces you to focus more on the
end and not the means. In any event, I think many here would agree that
unjustfied concern with the layout of data types is a sign of inexperience.
When I began programming in C I struggled for years with appropriate usage
of data types. Autoconf tests, macros, typedefs. I was convinced that it
mattered, if only because so many other programmers seemingly expended great
effort wrestling with the "problem".

The implications of C# and Java's decisions aren't as clear cut as you might
think.

Eventually you become comfortable with the notion that you can create
software in a world where all your constraints aren't predefined and
absolutely fixed for you. Amount of memory changes, CPUs get faster (or
slower in some cases). Networks provide higher (or lower) throughput; higher
(or lower) latency. And yes, in some languages even the properties of data
types can change. And if they didn't, it wouldn't matter one iota. At some
point you have to learn how to program in a manner which isn't at odds with
reality, unless you enjoy re-writing the same code over and over again. You
use the tools to solve the abstract problem; you shouldn't invent problems
where none need exist.

At the very least, that some programmers aren't bothered by this aspect of C
should give you pause.

Jan 15 '08 #21

P: n/a
"Bart C" <b...@freeuk.comwrote:
Bart C wrote:
I've always had a problem knowing exactly how wide my
integer variables were in C...
No, your problem is that you think you need precise fixed
width integers.

<snip>
Is there anywhere a development of C that has been brought
up-to-date and tidied up, to run on modern 32/64-bit CPUs
...
Yes. It was done back in the late 80's. Pity you missed it.
Still, it's not to late to catch up.

--
Peter
Jan 15 '08 #22

This discussion thread is closed

Replies have been disabled for this discussion.