32 or 64 bit processor info in C

C

CBFalconer

Eric said:
.... snip ...

As for the malloc example, I myself usually write an
assignment statement and a separate test. This is not so
much out of a concern that the whole thing would be too
long, but to direct the focus: "I will now allocate some
memory. (By the way, I'll also check for failure.)" But
sometimes I'll gang the whole thing together, particularly
during an initialization where I'm just going to exit the
program on a failure:

if ( (buff1 = malloc(N1 * sizeof *buff1) == NULL
|| (buff2 = malloc(N2 * sizeof *buff2) == NULL
|| (buff3 = malloc(N3 * sizeof *buff3) == NULL ) {
perror ("malloc");
fputs ("No memory; bye-bye!\n", stderr);
exit (EXIT_FAILURE);
}

A few mistakes there. You want:

buff1 = buff2 = buff3 = NULL;
if ( !(buff1 = malloc(N1 * sizeof *buff1)
|| !(buff2 = malloc(N2 * sizeof *buff2)
|| !(buff3 = malloc(N3 * sizeof *buff3) ) {
perror ("malloc");
free(buff1); free(buff2); free(buff3);
fputs ("No memory; bye-bye!\n", stderr);
exit (EXIT_FAILURE); /* or whatever */
}

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>
<http://www.aaxnet.com/editor/edit043.html>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
 
M

Malcolm McLean

Eric Sosman said:
McClean's example showed a perfectly simple, obvious
and easily-comprehended test, which he chose to decompose
into two statements. In the process he introduced a brand-
new variable (the point of his example was to try to expose
a difficulty concerning that unnecessary variable), plus two
additional operators. That sort of rearrangement is not
only obfuscatory (hiding a comparison behind a subtraction,
a la FORTRAN's three-way IF), but bug-inducing.
There is always a difficulty in illustrating psychological problems with
computer code, which is that a short example is more comprehensible than the
same construct encountered in real code.
In this case you could, legitimately, say "why not just eliminate the
variable altogether?" I used a comparison to make it obvious that the result
could go below zero, but we could just as easily have used the intermediate
several times in some other lines. It is not possible to eliminate all
intermediate variables from integer calculations. If we subtract two
size_ts, what do we hold the result in?

The answer is an ssize_t. Which for efficiency reasons is allowed to fail if
the difference in size_t's spans more than half the address space. The point
is that once we admit a fundamental, if subtle, change into the language,
the complications can percolate up, until we are left with quite major
changes.
 
E

Eric Sosman

CBFalconer said:
Eric Sosman wrote:
... snip ...

A few mistakes there. You want:

buff1 = buff2 = buff3 = NULL;
if ( !(buff1 = malloc(N1 * sizeof *buff1)
|| !(buff2 = malloc(N2 * sizeof *buff2)
|| !(buff3 = malloc(N3 * sizeof *buff3) ) {
perror ("malloc");
free(buff1); free(buff2); free(buff3);
fputs ("No memory; bye-bye!\n", stderr);
exit (EXIT_FAILURE); /* or whatever */
}

Sorry: why would I want that? All you've done (unless I'm
overlooking something) is convert `x==NULL' into `!x' and to
add a few extra free() calls that are implicit[*] in the exit()
anyhow. I see no "mistakes" that the rewrite corrects.

[*] Context: I do not consider environments where exit() and
abort() fail to release allocated memory. Rumors of such have
surfaced from time to time, but none I've heard have been
credible. And don't shout "Embedded!" at me: obviously in an
embedded environment one wouldn't adopt so simplistic an error
"recovery" scenario in the first place.
 
C

CBFalconer

Eric said:
CBFalconer said:
.... snip ...

A few mistakes there. You want:

buff1 = buff2 = buff3 = NULL;
if ( !(buff1 = malloc(N1 * sizeof *buff1)
|| !(buff2 = malloc(N2 * sizeof *buff2)
|| !(buff3 = malloc(N3 * sizeof *buff3) ) {
perror ("malloc");
free(buff1); free(buff2); free(buff3);
fputs ("No memory; bye-bye!\n", stderr);
exit (EXIT_FAILURE); /* or whatever */
}

Sorry: why would I want that? All you've done (unless I'm
overlooking something) is convert `x==NULL' into `!x' and to
add a few extra free() calls that are implicit[*] in the exit()
anyhow. I see no "mistakes" that the rewrite corrects.

[*] Context: I do not consider environments where exit() and
abort() fail to release allocated memory. Rumors of such have
surfaced from time to time, but none I've heard have been
credible. And don't shout "Embedded!" at me: obviously in an
embedded environment one wouldn't adopt so simplistic an error
"recovery" scenario in the first place.

And I went and repeated your fundamental mistake of omitting
trailing parens on each term! However I don't consider "exit(...)"
to be a complete commitment. You may well want to change that to
something more reasonable for the system.

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>
<http://www.aaxnet.com/editor/edit043.html>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
 
F

Flash Gordon

Malcolm McLean wrote, On 18/04/07 23:35:

space. The point is that once we admit a fundamental, if subtle, change
into the language, the complications can percolate up, until we are left
with quite major changes.

So stop suggesting changing the language. The int type was never been
the size of the address bus except by coincidence and size_t has been in
the language since at least 1989 if not earlier.
 
R

Richard Bos

Malcolm McLean said:
Then it can index all of memory. I like to use integers to index into
arrays.

You keep confusing integers with int. Don't do that.
If an int isn't guaranteed to be able to index an arbitrary array, that
creates difficulties.

No, it doesn't. You can use another integer. In fact, why not use the
integer that was specifically intended for that purpose? You might know
it; it's called size_t.
This is turning into a good litmus test to sort out those who understand
from those who don't.

Yes, it is. Since you're the only one appearing not to understand that
we have different integers for different purposes, and that this is a
good thing... draw your own conclusion.

Richard
 
R

Richard Bos

Malcolm McLean said:
The answer is an ssize_t. Which for efficiency reasons is allowed to fail if
the difference in size_t's spans more than half the address space.

Oh FFS, use ptrdiff_t already! Have you even _read_ the Standard, or are
you just talking out of blithe ignorance? ssize_t is completely
unnecessary, and if you knew C well, you'd know that.
The point is that once we admit a fundamental, if subtle, change into
the language,

No, the point is that having different size integers, and size_t for
indices, is _not_ a change. That's how C has been since at least 1989.

Richard
 
A

Army1987

Malcolm McLean said:
Keith Thompson said:
On the other hand, sometimes it's ok to use int to index into an
array, if, for example, you happen to know that the array cannot have
more than 32768 elements. The indexing operation takes one pointer
operand (often a converted array name) and one integer operand; the
integer operand can be of any integer type, including int, size_t, and
even _Bool if your compiler supports it.
This is the problem.

int count_spaces(char *str)
{
int i;
int answer = 0;

for(i=0;str;i++)
if(str == ' ')
answer++;

return answer;
}

Perfectly unexceptional code. In fact it is unlikely that anyone is going
to want that routine on anything other than a line limited elsewhere to be
a thousand or so characters.
But someone might, just might, pass in a really long string. So those ints
have got to be size_ts to be strictly correct. So size_t is propagating up
out type.


As for i, you could use while(*str++) so you wouldn't need it.
As for answer, an int is required to handle all the cases when there are
less than 2^15 spaces. If this is a problem, use long, which is required to
go up to 2^31. If you really think you might pass a string with more than 2
billion space characters, that's your problem. If you use C99, you can use
long long, and I don't think one will ever, ever need a string whose length
is more than one gigabyte times the human population of the Earth.
And you don't want to use an unsigned type. For example, you might want the
function to test wheter str is a null pointer and then return -1. Or you
might use a function with
n = count_spaces(str1);
while (n-- >= 0)
in it (not a very good thing to do, but some people might do that).
Now consider this

foo(char *str1, char *str2)
{
hackme = strlen(str1) - count_spaces(str2);
if(hackme < 0)
bar(str1, str2);
else
baz(str12, str2);
}

Again nothing too exceptional about this code. Typical rather horrid flow
control logic. What type would you say hackme should be?

int, or long if you think that it is possible that the function will ever be
called with strings longer than INT_MAX.
Or better, simplily use if(strlen(str1) < (size_t)count_spaces(str2)).
 
M

Malcolm McLean

Richard Bos said:
Oh FFS, use ptrdiff_t already! Have you even _read_ the Standard, or are
you just talking out of blithe ignorance? ssize_t is completely
unnecessary, and if you knew C well, you'd know that.
In the example we have two calls to functions yielding size_ts. We then want
the difference, which can be negative. However ptrdiff_t is not appropriate
since the operands are not pointers. ssize_t is intended for the purpose.
No, the point is that having different size integers, and size_t for
indices, is _not_ a change. That's how C has been since at least 1989.
size_t is a change. It is not present in K and R C, and rightly so. Another
change is not having int as the natural integer type for the platform.
Whilst there is an argument for having fixed-size types in a language, C
chose the other route. We are now seeing a reversal of policy so that
existing 32-bit code won't break under 64 bits. That is, badly-written
32-bit code. If it was written properly it wouldn't assume 32 bit ints and
longs.
I am arguing for keeping the existing policy that has served C well for so
long. size_t was tolerable as long as no programmer worth his salt used it.
The danger is that the move to 64 bits will encourage or even force its
widespread use.
 
I

Ian Collins

Malcolm said:
size_t is a change. It is not present in K and R C, and rightly so.

Ah, so you are objecting to C89 now. It's a little late for that.
Another change is not having int as the natural integer type for the
platform.

But 32 bit int is a natural integer type for most contemporary 64 bit
systems.
Whilst there is an argument for having fixed-size types in a
language, C chose the other route. We are now seeing a reversal of
policy so that existing 32-bit code won't break under 64 bits. That is,
badly-written 32-bit code. If it was written properly it wouldn't assume
32 bit ints and longs.

So you are labelling the BSD networking code as bad? The assumption
that long is 32 bits is pretty widespread there.

When ever C hits the real world, developers have added fixed size types.
Now they are standardised. Good.
 
K

Keith Thompson

Malcolm McLean said:
In the example we have two calls to functions yielding size_ts. We
then want the difference, which can be negative. However ptrdiff_t is
not appropriate since the operands are not pointers. ssize_t is
intended for the purpose.

ssize_t is not part of the C standard (it's defined by POSIX). I
wouldn't mind if it were added to standard C. ssize_t, where it
exists, is a signed type the same size as the unsigned type size_t.
ptrdiff_t, though it's not defined that way, is very likely to be a
signed type the same size as size_t, so using it to store the
difference between two size_t values (where the result may be negative
and is unlikely to overflow) is not unreasonable.

If you want to be sure you can avoid overflow (or as sure as it's
possible to be), you can use intmax_t if it's available, or long if
you want to maintain C90 compatibility.
size_t is a change. It is not present in K and R C, and rightly
so.

A lot of things aren't in K&R C. Time has passed. size_t was
introduced in the 1989 ANSI standard; the time to complain about it
was about 20 years ago.
Another change is not having int as the natural integer type for
the platform.

That has always been an unenforceable requirement. There is no clear
definition for the phrase "natural integer type for the platform" (or
as the C99 standard says, "the natural size suggested by the
architecture of the execution environment"). And if there were a
clear definition, I seriously doubt that it would involve the size of
the address bus.
Whilst there is an argument for having fixed-size types
in a language, C chose the other route. We are now seeing a reversal
of policy so that existing 32-bit code won't break under 64 bits. That
is, badly-written 32-bit code. If it was written properly it wouldn't
assume 32 bit ints and longs.

The same thing happened during the transition from 16-bit to 32-bit
architectures; there were implementations for 32-bit machines that had
16-bit ints. Somehow we muddled through.
I am arguing for keeping the existing policy that has served C well
for so long. size_t was tolerable as long as no programmer worth his
salt used it. The danger is that the move to 64 bits will encourage or
even force its widespread use.

You are not arguing for leaving C as it is; you are arguing for
changing it to what you want it to be. If you don't like C the way
it's actually defined, that's fine. Arguing that the way you want it
to be is the way it actually is doesn't help your case.
 
E

Eric Sosman

Malcolm McLean wrote On 04/20/07 17:58,:
Richard Bos said:
[...]

No, the point is that having different size integers, and size_t for
indices, is _not_ a change. That's how C has been since at least 1989.

size_t is a change. It is not present in K and R C, and rightly so. Another

K&R C also lacked void and void*, long double,
function prototypes, <stdarg.h> and variadic functions,
<stddef.h> said:
change is not having int as the natural integer type for the platform.

You keep asserting this, but it was never so. int was
always a "useful" size that "made sense" for the platform.
I've used eight-bit machines with C implementations, but
never have I seen an 8-bit int.
Whilst there is an argument for having fixed-size types in a language, C
chose the other route. We are now seeing a reversal of policy so that
existing 32-bit code won't break under 64 bits. That is, badly-written
32-bit code. If it was written properly it wouldn't assume 32 bit ints and
longs.

Part of the "Spirit of C" is (I'm not making this up;
it's in the Rationale) is "Trust the programmer." It turns
out that some programmers are untrustworthy, which is too
bad -- but the cure isn't to dumb down C, but to smarten up
the bad programmers.

And do you imagine that expanding int to 64 or 128 or
1024 bits will magically fix all that bad code? Then it's
obvious you've had NO experience in porting code to an
environment where the data type sizes change. If you had
any such experience, you wouldn't believe such folderol.
I am arguing for keeping the existing policy that has served C well for so
long.

I am arguing for keeping the existing policy that assigns
colors to all C's fundamental data types. ("But there is no
such policy, and never has been!") Right you are, Jocko,
right you are.
size_t was tolerable as long as no programmer worth his salt used it.
The danger is that the move to 64 bits will encourage or even force its
widespread use.

"It's a poor workman who blames his tools."
 
K

Keith Thompson

Ian Collins said:
Malcolm McLean wrote: [...]
Whilst there is an argument for having fixed-size types in a
language, C chose the other route. We are now seeing a reversal of
policy so that existing 32-bit code won't break under 64 bits. That is,
badly-written 32-bit code. If it was written properly it wouldn't assume
32 bit ints and longs.

So you are labelling the BSD networking code as bad? The assumption
that long is 32 bits is pretty widespread there.

Is it? If so, I'd say that's a bad assumption. I'd be very surprised
if that code isn't already running on systems with 64-bit longs.
When ever C hits the real world, developers have added fixed size types.
Now they are standardised. Good.

Agreed. Though I suspect fixed size types tend to be overused. In
many cases, what you really need is a type able to represent (at
least) some specified range of values. C99's <stdint.h>,
unfortunately IMHO, gave the easy-to-remember names to the exact-width
types rather than the potentially more useful least-width types.

For example:

int_least32_t is the narrowest signed type of at least 32 bits.

int_fast32_t is the "fastest" signed type of at least 32 bits.

int32_t is *exactly* 32 bits wide; if there is no such type,
int32_t doesn't exist.

On a 64-bit CPU, for example, int_least32_t might be 32 bits and
int_fast32_t might be 64 bits.

I think that int32_t, the exact-width type, is really needed only for
conformance to some externally imposed data layout. For internal
numeric calculations, int_fast32_t or int_least32_t is more
appropriate, depending on whether you need large arrays. But since
the name "int32_t" is more obvious, a lot of programmers are going to
use it unnecessarily.

That's probably not *too* bad. If int32_t exists, it's going to be
the same as int_least32_t, and if it doesn't, the code will fail to
compile in a rather obvious manner. (But then the programmer may be
tempted to define his own "int32_t" that's actually 64 bits.)

IMHO, it would have been better to define:

int_least32_t
int_fast32_t
int_exact32_t

or perhaps even to introduce a new syntax for declaring such types
rather than using ad hoc typedefs.
 
I

Ian Collins

Keith said:
Ian Collins said:
Malcolm McLean wrote:
[...]
Whilst there is an argument for having fixed-size types in a
language, C chose the other route. We are now seeing a reversal of
policy so that existing 32-bit code won't break under 64 bits. That is,
badly-written 32-bit code. If it was written properly it wouldn't assume
32 bit ints and longs.

So you are labelling the BSD networking code as bad? The assumption
that long is 32 bits is pretty widespread there.

Is it? If so, I'd say that's a bad assumption. I'd be very surprised
if that code isn't already running on systems with 64-bit longs.
Yes, it has been for a long time, I was referring to the earlier code
where unsigned long is used extensively for 32 bit IP addresses. Even
some for the function names are a give away, ntohl/htonl for instance.
Agreed. Though I suspect fixed size types tend to be overused. In
many cases, what you really need is a type able to represent (at
least) some specified range of values. C99's <stdint.h>,
unfortunately IMHO, gave the easy-to-remember names to the exact-width
types rather than the potentially more useful least-width types.
Agreed.
 
M

Malcolm McLean

Eric Sosman said:
Malcolm McLean wrote On 04/20/07 17:58,:


You keep asserting this, but it was never so. int was
always a "useful" size that "made sense" for the platform.
I've used eight-bit machines with C implementations, but
never have I seen an 8-bit int.
Your machine had an eight bit address bus?
There is a bit of wooliness in the "natural integer type". However generally
it is the size needed to index the largest possible array, which generally
boils down to the size of the address bus, but not on old x86s because of
the weirdness of the architecture.
On a machine with 64 bits of flat address space and a 64 bit data register
file the natural integer size is quite clearly 64 bits. At the moment there
might be a performace case for using 32-bit integers to conserve cache
space. I've not said that all the good arguments are on my side. However I
suspect that this issue will prove to be quite short-lived.
 
I

Ian Collins

Malcolm said:
Your machine had an eight bit address bus?
There is a bit of wooliness in the "natural integer type". However
generally it is the size needed to index the largest possible array,
which generally boils down to the size of the address bus, but not on
old x86s because of the weirdness of the architecture.

No, it can't do that, int is a signed type, so it can never index the
largest possible array.
On a machine with 64 bits of flat address space and a 64 bit data
register file the natural integer size is quite clearly 64 bits. At the
moment there might be a performace case for using 32-bit integers to
conserve cache space. I've not said that all the good arguments are on
my side. However I suspect that this issue will prove to be quite
short-lived.
Considering 64 bit systems have been in widespread use for over a
decade, short is a relative term.
 
R

Richard Heathfield

Ian Collins said:
Malcolm McLean wrote:

So you are labelling the BSD networking code as bad? The assumption
that long is 32 bits is pretty widespread there.

To be diplomatic, let us just say that the BSD networking code would
have been *even better* if it didn't make invalid assumptions about
integer type sizes.
When ever C hits the real world, developers have added fixed size
types.
Now they are standardised. Good.

Whenever language designers specify fixed size types, they have to come
back later and specify some more. Bad.
 
I

Ian Collins

Richard said:
Ian Collins said:


Whenever language designers specify fixed size types, they have to come
back later and specify some more. Bad.
If don't specify the type, everyone else who wants it has to add their
own, so we ended up with typedefs like U8, INT16 and just about every
other possible naming of fixed types. At least the standard now sets a
naming convention.
 
R

Richard Heathfield

Ian Collins said:
If don't specify the type, everyone else who wants it has to add their
own,

Not quite everyone.
so we ended up with typedefs like U8, INT16 and just about every
other possible naming of fixed types. At least the standard now sets
a naming convention.

Which can safely be ignored, on the whole.
 

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
474,434
Messages
2,571,690
Members
48,796
Latest member
Greg L.

Latest Threads

Top