size_t problems

I

Ian Collins

CBFalconer said:
Keith Thompson wrote:
.... snip ...

It does if you are passing a pointer to a const item. That way you
can protect the parameter and avoid copying large objects. Such
as, but not limited to, strings.
Why would you want to? That implies writing something like

void f( const int* const );

which is rather pointless.

simply writing

void f( const int* );

protects the pointed to item. You can change the value of the pointer,
but it still points to constant data.

I'm not sure where "avoid copying large objects" comes form, care to
elaborate?
 
M

Malcolm McLean

Ben Pfaff said:
My code does in fact end up using size_t quite often. If I were
perfectly consistent, it would probably use size_t even more
often. Why is that a problem?
If you are indexing an arbitrary-length array, effectively now it is an
error to use int. That's a big change from what most people would recognise
as "C". It is also very undesireable that i, which holds the index, is
described as a "size_t" when it certainly doesn't hold a size. N, the count,
doesn't hold an amount of memory either, but is also a size_t.

Thnen you've got the problem of two standards, in fact 14 standards at last
count, for holding integers. That makes it harder and harder to make
functions fit together. Code is littered with casts because cursorxy takes
two int *s, whilst drawxy takes two size_ts.

The best solution is to to say "int is a type which can index any array"
which means that int must have the same number of bits as a char pointer,
which on 99% of platforms is no problem at all. By making the standard
slightly loose the wierdos can break this rule - if char *'s have an extra
four bits, because underlying bytes are 32 bits, it might be unacceptably
inefficient to have ints large enough to hold them, but the loss of the
ability to index strings taking up an eighth of the address space or more,
without special code, isn't too bad a loss, and the problem won't be solved
by size_t.

There is also the issue of signedness. Again, this is more theoretical than
practical. In practise you can live without the extra bit, because it only a
problem handling

The other problem is backwards compatibility with legacy libraries. However,
as I pointed out, 64 bits of memory will be the maximum for a long time to
come. We mustn't damage C now purely to call a few APIs left over from
32-bit days.
 
M

Malcolm McLean

Richard Heathfield said:
Charlton Wilbur said:

But you don't have /any/ dollars in your bank account. What you have is
a number which represents a dollar /balance/ - it is, if you like, the
difference between the number of dollars the bank owes you and the
number of dollars you owe the bank. It can, however, reasonably be
regarded as a monetary amount, and as such can of course be negative.
The number of dollars in your wallet is /also/ a monetary amount, and
monetary amounts can be negative. Of course, the number of dollars in
your wallet cannot be negative, any more than 6 can be negative, even
though 6 is an int and ints can be negative.
It is also possible to have imaginary money, in your paycheck. Happened to
me once.
 
C

CBFalconer

Ian said:
Why would you want to? That implies writing something like

void f( const int* const );

I think you are confused. "void f(const int* param)" declares param
to be a pointer pointing to a const int (or the first item in a
const array of ints). There is no second const.

However "void f(const struct blah param)" declares param to be an
initialized (and const) copy of something that originated as a
struct blah. The entire struct has been copied into the parameter
space of the function f. This copying is what can be avoided by
using a pointer, as in "void f(const struct blah *param)".

You just can't pass an array by value in C without embedding it in
a suitable struct.
 
J

jacob navia

spacecriter said:
I assume that you don't want to redefine s as a size_t because it may be
used elsewhere as an int, and you would rather not track down everywhere it
may be used.

So why not replace all the strlen() calls with your own function (maybe
call it i_strlen(), or somesuch name) that returns an int?
That would be a good solution!

THANKS!

jacob
 
K

Keith Thompson

CBFalconer said:
Keith Thompson wrote:
... snip ...

It does if you are passing a pointer to a const item. That way you
can protect the parameter and avoid copying large objects. Such
as, but not limited to, strings.

I was referring only to applying 'const' to the parameter itself. (I
could have been clearer.)
 
I

Ian Collins

CBFalconer said:
I think you are confused. "void f(const int* param)" declares param
to be a pointer pointing to a const int (or the first item in a
const array of ints). There is no second const.
Confused by what you wrote maybe? "That way you can protect the
parameter" the only way you can prevent the parameter being modified is
to make the parameter const. I (and I think Keith) was pointing out
that making the parameter type const is seldom, if ever, useful.
 
R

Richard Heathfield

Malcolm McLean said:

If you are indexing an arbitrary-length array, effectively now it is
an error to use int.
Yes.

That's a big change from what most people would recognise as "C".

No. It's the way I've been using C ever since I learned how to do it
properly, rather than follow the Schildt-style advice I had received up
to that point.
It is also very undesireable that i, which holds the
index, is described as a "size_t" when it certainly doesn't hold a
size.

I'll agree that an index doesn't hold a size...
N, the count, doesn't hold an amount of memory either, but is
also a size_t.

....but I can't agree that it doesn't hold a count.
Thnen you've got the problem of two standards, in fact 14 standards at
last count, for holding integers.

The integer types that C90 must support (and which are required to be
integer types) are char, signed char, unsigned char, short, unsigned
short, int, unsigned int, long, unsigned long, wchar_t, size_t,
ptrdiff_t, sig_atomic_t - which is thirteen.

C99 adds long long and unsigned long long, making at least fifteen, and
then there are an indeterminate number of intsuch-and-such_t types,
making a count impractical.

Either way, your count, like your argument, is wrong.
That makes it harder and harder to
make functions fit together.

No, it doesn't.
Code is littered with casts because
cursorxy takes two int *s, whilst drawxy takes two size_ts.

The only code that is littered with casts is broken code.
The best solution is to to say "int is a type which can index any
array" which means that int must have the same number of bits as a
char pointer, which on 99% of platforms is no problem at all.

No, the best solution is to use size_t where appropriate, and int where
appropriate.

The other problem is backwards compatibility with legacy libraries.

Not a problem at all. All you have to do is recompile the library with
the new compiler. If that breaks the library, it probably wasn't a very
good library anyway.
However, as I pointed out, 64 bits of memory will be the maximum for a
long time to come.

Ha. And perhaps ha.
We mustn't damage C now purely to call a few APIs left over from
32-bit days.

C has never /had/ 32-bit days. C doesn't care how many bits a byte or an
int or a size_t or an address bus has, subject to certain basic minima
which are considerably lower than 32. Write your code to depend on
64-bit ints, and you can bet your bottom dollar it'll break one day,
and you'll be resisting the change to 128 or 256 or whatever it is out
of sheer fear of breakage. That's your problem. The solution? Stop
depending on particular sizes, and work out how to program in the
large.
 
C

CBFalconer

jacob said:
That would be a good solution!

No, that would be a temporary glossing over, avoiding fixing the
fundamental problem, and postponing the fix (or abandonment) until
later, with attendant confusion of the code. Not wise in the long
term. Some things are better done right.
 
K

Keith Thompson

jacob navia said:
That would be a good solution!

THANKS!

Hmm, sounds familiar.

| I suppose you could write a strlen wrapper that calls the real strlen,
| checks whether the result exceeds INT_MAX (if you think that check is
| worth doing), and then returns the result as an int. That's assuming
| strlen calls are the only things triggering the warnings. And you'd
| still have to make hundreds of changes in the code.

<http://groups.google.com/group/comp.lang.c/msg/3ef33439c43be6ac>
 
K

Keith Thompson

Malcolm McLean said:
If you are indexing an arbitrary-length array, effectively now it is
an error to use int. That's a big change from what most people would
recognise as "C".

The "big change" was made in 1989.
It is also very undesireable that i, which holds the
index, is described as a "size_t" when it certainly doesn't hold a
size. N, the count, doesn't hold an amount of memory either, but is
also a size_t.

Then you should add this to your code:

typedef size_t size_or_count_or_index_t;

Or just think of size_t as something more general than its name
implies.
Thnen you've got the problem of two standards, in fact 14 standards at
last count, for holding integers. That makes it harder and harder to
make functions fit together. Code is littered with casts because
cursorxy takes two int *s, whilst drawxy takes two size_ts.

They're called "types", not "standards".

I actually tend to think that the number of standard types in C has
gotten to be a bit much. It's probably inevitable given the way C has
evolved, but it's something I'd do differently if I were designing a
new language from scratch. Rather than having a dozen or so
predefined integer types, I think I'd prefer a general method to
define types.

We wouldn't tolerate a language with just a dozen or so predefined
array types, each with a fixed length that varies from one
implementation to another, but we accept it for integer types. (And
yes, there are reasons for the difference.)

But this is just idle speculation. C is what it is.
 
R

Richard Tobin

jacob navia said:
#define strlen Strlen_i;

These is probably not legal, at least in theory. Doing it after all
includes will probably work, though.

-- Richard
 
K

Keith Thompson

CBFalconer said:
No, that would be a temporary glossing over, avoiding fixing the
fundamental problem, and postponing the fix (or abandonment) until
later, with attendant confusion of the code. Not wise in the long
term. Some things are better done right.

If he can be certain that none of the strings he's dealing with will
ever exceed 32767 bytes (say, they're people's names), then it's not a
horribly bad solution, especially if his wrapper invokes the real
strlen() and checks the result before returning it as an int.
 
J

jacob navia

Keith said:
Hmm, sounds familiar.

| I suppose you could write a strlen wrapper that calls the real strlen,
| checks whether the result exceeds INT_MAX (if you think that check is
| worth doing), and then returns the result as an int. That's assuming
| strlen calls are the only things triggering the warnings. And you'd
| still have to make hundreds of changes in the code.

NO!

Just

int Strlen_i(char *s)
{
char *start=s;
while (*s)
s++;
return s-start;
}
#define strlen Strlen_i;
 
R

Richard

jacob navia said:
NO!

Just

int Strlen_i(char *s)
{
char *start=s;
while (*s)
s++;
return s-start;
}
#define strlen Strlen_i;



int Strlen_i(char *s)
{
int i=0;
while (*s++ && ++i);
return i;
}

why? It returns in the case of a mad string (ie bigger than int) when i
wraps to 0. Assuming i does that in the standard.
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top