Use of Long and Long Long

B

Bart C

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);

}
 
V

vippstar

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 said:
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.
 
F

Flash Gordon

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.
 
U

user923005

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>
 
E

Eric Sosman

Bart said:
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 said:
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 said:
(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.]
 
W

Walter Roberson

user923005 said:
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.
 
C

CBFalconer

Bart said:
.... 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.
 
J

jameskuyper

Bart said:
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
 
W

William Ahern

'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 ;)
 
W

Walter Roberson

(e-mail address removed) wrote:
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.
 
W

Walter Roberson

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.
 
C

CBFalconer

Walter said:
.... 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/>
 
B

Bart C

Flash said:
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.

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
 
B

Bart C

CBFalconer said:
Bart C wrote:

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
 
J

Jack Klein

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
 
F

Flash Gordon

Bart C wrote, On 10/01/08 01:16:
Flash said:
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?
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.
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).
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.
 
J

James Kuyper

Flash said:
Bart C wrote, On 10/01/08 01:16:
Flash said:
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).
 
B

Bart C

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

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.
 
B

Bart C

Jack said:
comp.lang.c:

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]
 
F

Flash Gordon

Bart C wrote, On 10/01/08 12:20:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top