C89, size_t, and long

Y

Yevgen Muntyan

Hey,

I was reading C99 Rationale, and it has the following two QUIET CHANGE
paragraphs:

6.5.3.4: "With the introduction of the long long and extended integer
types, the sizeof operator may yield a value that exceeds the range
of an unsigned long."

6.5.6: "With the introduction of the long long and extended integer
types, the subtraction of pointers may return a value that exceeds the
range of a long."

Was it required by C89 that result of sizeof() fits into unsigned long,
and that pointer subtraction result fits into long? If yes, then MS
Win64 implementation is not C89-conforming (while sizeof case may be
arguable, I guess, we certainly can ask to malloc more than ULONG_MAX
bytes, and get pointer arithmetics which needs more than (unsigned)
long). If no, why these two paragraphs, if programs which relied on long
being big enough were already broken?

Yevgen
 
E

Eric Sosman

Yevgen Muntyan wrote On 03/14/07 14:26,:
Hey,

I was reading C99 Rationale, and it has the following two QUIET CHANGE
paragraphs:

6.5.3.4: "With the introduction of the long long and extended integer
types, the sizeof operator may yield a value that exceeds the range
of an unsigned long."

6.5.6: "With the introduction of the long long and extended integer
types, the subtraction of pointers may return a value that exceeds the
range of a long."

Was it required by C89 that result of sizeof() fits into unsigned long,
and that pointer subtraction result fits into long?

"Yes" and "Almost," respectively. C89 offered a fixed
set of integer types, of which {,un}signed long was the widest.
The implementation was free to provide additional types that
behaved like integers, but they were not "integer types" as
C89 defined them. C89 also required that size_t and ptrdiff_t
be aliases for "integer types," so they could not be wider than
long. If an implementation offered wider types, they were not
"integer types" and hence were not candidates for size_t and
ptrdiff_t.

On machines whose longs are the same width as their pointers
(more generally, no wider than their pointers), this means that
ptrdiff_t cannot be wide enough to express the result of all
pointer subtractions. An easy example:

char *p = malloc(LONG_MAX + 2u); /* assume success */
char *q = p + LONG_MAX + 2u;
ptrdiff_t delta = q - p;

We will now have p < q but (probably) delta < 0.
If yes, then MS
Win64 implementation is not C89-conforming (while sizeof case may be
arguable, I guess, we certainly can ask to malloc more than ULONG_MAX
bytes, and get pointer arithmetics which needs more than (unsigned)
long). If no, why these two paragraphs, if programs which relied on long
being big enough were already broken?

I don't know MS' Win64 implementation well enough to comment
on whether it's broken or not. As for programs that assumed
size_t and ptrdiff_t were no wider than long, no: They were not
broken under C89's rules, because C89 implied the truth of the
assumption. C99 changed the rules, allowing the implementation-
defined "exotic" types to be counted among the "integer types,"
and this change could break some programs that relied on the old
rule. Hence the "Quiet Change" warnings.
 
Y

Yevgen Muntyan

Eric said:
Yevgen Muntyan wrote On 03/14/07 14:26,:

"Yes" and "Almost," respectively. C89 offered a fixed
set of integer types, of which {,un}signed long was the widest.
The implementation was free to provide additional types that
behaved like integers, but they were not "integer types" as
C89 defined them. C89 also required that size_t and ptrdiff_t
be aliases for "integer types," so they could not be wider than
long. If an implementation offered wider types, they were not
"integer types" and hence were not candidates for size_t and
ptrdiff_t.

On machines whose longs are the same width as their pointers
(more generally, no wider than their pointers), this means that
ptrdiff_t cannot be wide enough to express the result of all
pointer subtractions. An easy example:

char *p = malloc(LONG_MAX + 2u); /* assume success */
char *q = p + LONG_MAX + 2u;
ptrdiff_t delta = q - p;

We will now have p < q but (probably) delta < 0.


I don't know MS' Win64 implementation well enough to comment
on whether it's broken or not.

It has 32-bit long, same as int, and naturally 64-bit size_t.
As for programs that assumed
size_t and ptrdiff_t were no wider than long, no: They were not
broken under C89's rules, because C89 implied the truth of the
assumption.

Then these programs may be broken on Win64, right? Say, this code:

void do_something (void *buf, unsigned long len)
{
memset (buf, 1, len);
}

int main (void)
{
size_t i;
size_t size = BIG_NUMBER;
char *p = malloc (size);
if (p)
{
do_something (p, size);
assert (p[size-1]);
}
return 0;
}

BIG_NUMBER can be defined as some square root of SIZE_MAX+1 multiplied
by two or something, so we don't need to invent functions which get
us a big buffer. I guess MS estimated somehow how much of their code
uses long as 32-bit int, and decided it's more than code which uses
unsigned long as size_t. Anyway, is MS Win64 implementation not
C89-conforming (it's an important thing, isn't it)? Or I do miss
something?

Thanks,
Yevgen
 
E

Eric Sosman

Yevgen Muntyan wrote On 03/14/07 15:14,:
Eric said:
Yevgen Muntyan wrote On 03/14/07 14:26,:
[...]
Was it required by C89 that result of sizeof() fits into unsigned long,
and that pointer subtraction result fits into long? [...]
If yes, then MS
Win64 implementation is not C89-conforming (while sizeof case may be
arguable, I guess, we certainly can ask to malloc more than ULONG_MAX
bytes, and get pointer arithmetics which needs more than (unsigned)
long). [...]

I don't know MS' Win64 implementation well enough to comment
on whether it's broken or not.

It has 32-bit long, same as int, and naturally 64-bit size_t.

If size_t is wider than long, the implementation cannot
conform to C89. It could, however, conform to C99, with
size_t being as wide as long long or as some other wide type.
One of the (many) things I don't know about MS Win64 is what
standards it claims to conform to.
As for programs that assumed
size_t and ptrdiff_t were no wider than long, no: They were not
broken under C89's rules, because C89 implied the truth of the
assumption.

Then these programs may be broken on Win64, right? Say, this code:

void do_something (void *buf, unsigned long len)
{
memset (buf, 1, len);
}

int main (void)
{
size_t i;
size_t size = BIG_NUMBER;
char *p = malloc (size);
if (p)
{
do_something (p, size);
assert (p[size-1]);
}
return 0;
}

If malloc() succeeds, this program works under C89 but
might not work on a C99 implementation.
[...] Anyway, is MS Win64 implementation not
C89-conforming (it's an important thing, isn't it)? Or I do miss
something?

From your description, it cannot be a conforming C89
implementation. Is that important? Well, to whom?
 
Y

Yevgen Muntyan

Eric said:
Yevgen Muntyan wrote On 03/14/07 15:14,:
Eric said:
Yevgen Muntyan wrote On 03/14/07 14:26,:
[...]
Was it required by C89 that result of sizeof() fits into unsigned long,
and that pointer subtraction result fits into long? [...]
If yes, then MS
Win64 implementation is not C89-conforming (while sizeof case may be
arguable, I guess, we certainly can ask to malloc more than ULONG_MAX
bytes, and get pointer arithmetics which needs more than (unsigned)
long). [...]
I don't know MS' Win64 implementation well enough to comment
on whether it's broken or not.
It has 32-bit long, same as int, and naturally 64-bit size_t.

If size_t is wider than long, the implementation cannot
conform to C89. It could, however, conform to C99, with
size_t being as wide as long long or as some other wide type.
One of the (many) things I don't know about MS Win64 is what
standards it claims to conform to.

It claims conformance to C90. It does not conform to C99.

....
[...] Anyway, is MS Win64 implementation not
C89-conforming (it's an important thing, isn't it)? Or I do miss
something?

From your description, it cannot be a conforming C89
implementation. Is that important? Well, to whom?

Well, to people who want to write code which would work on win64.

Yevgen
 
E

Eric Sosman

Yevgen Muntyan wrote On 03/14/07 15:57,:
Eric said:
If size_t is wider than long, the implementation cannot
conform to C89. [...]

It claims conformance to C90. It does not conform to C99.

In that case, the claim is incorrect, and testably so:

size_t u = -1;
unsigned long v = u;
assert (u == v);
[...] Anyway, is MS Win64 implementation not
C89-conforming (it's an important thing, isn't it)? Or I do miss
something?

From your description, it cannot be a conforming C89
implementation. Is that important? Well, to whom?


Well, to people who want to write code which would work on win64.

Observe that this nonconformance only affects code that
does any of

- Type-punning via unions or pointers to access a size_t
object as an unsigned long or vice versa (or similar punning
between ptrdiff_t and signed long). Such code is broken already
under all versions of the Standard, so it doesn't bother me if
MS causes additional breakage.

- Computing sizes > ULONG_MAX bytes (>= 4GB, in this case)
and converting them to unsigned long. First, you'd need to
have a reason to compute such large sizes; all right, on a
64-bit system I'll grant that such reasons may arise. But
then you'd need to write unsigned long instead of size_t to
get into trouble; why would you do that?

- To answer the question, you might do that to print the
size_t value using "%lu" or something of the kind. In this
case, you could get the wrong answer printed, which might or
might not affect the behavior of the rest of the program. As
far as I can imagine, this is the only case you need to worry
about, the only case in "legitimate" code where the fact that
size_t is wider than unsigned long could cause trouble. Be
on your guard!
 
K

Keith Thompson

Yevgen Muntyan said:
Eric Sosman wrote: [...]
I don't know MS' Win64 implementation well enough to comment
on whether it's broken or not.

It has 32-bit long, same as int, and naturally 64-bit size_t.

How is size_t defined? Does the implementation provide an "unsigned
long long" type and make size_t an alias for that? Or does it use
some non-standard syntax for its 64-bit types?
 
Y

Yevgen Muntyan

Eric said:
Yevgen Muntyan wrote On 03/14/07 15:57,:
Eric said:
If size_t is wider than long, the implementation cannot
conform to C89. [...]
It claims conformance to C90. It does not conform to C99.

In that case, the claim is incorrect, and testably so:

size_t u = -1;
unsigned long v = u;
assert (u == v);
[...] Anyway, is MS Win64 implementation not
C89-conforming (it's an important thing, isn't it)? Or I do miss
something?
From your description, it cannot be a conforming C89
implementation. Is that important? Well, to whom?

Well, to people who want to write code which would work on win64.

Observe that this nonconformance only affects code that
does any of

- Type-punning ...

- Computing sizes > ULONG_MAX bytes (>= 4GB, in this case)
and converting them to unsigned long. First, you'd need to
have a reason to compute such large sizes; all right, on a
64-bit system I'll grant that such reasons may arise. But
then you'd need to write unsigned long instead of size_t to
get into trouble; why would you do that?

Answer to "why" may be wrong, but it won't change much if it's
already done. There is lot of code which assumes long
is big enough, and one must be aware of it (it's a real issue,
with real software).
There is more important thing to it. This single non-conformance
is simple: use appropriate types and you're good. But if MS broke
this thing (which breaks code, i.e. it's not some academic issue),
then what else is broken? It's a psychological issue (paranoia?).
- To answer the question, you might do that to print the
size_t value using "%lu" or something of the kind. In this
case, you could get the wrong answer printed, which might or
might not affect the behavior of the rest of the program. As
far as I can imagine, this is the only case you need to worry
about, the only case in "legitimate" code where the fact that
size_t is wider than unsigned long could cause trouble.

You're saying it's legitimate. But how is casting size_t
to unsigned long more legitimate than

int process_some_data (char *data, unsigned long len);

Yevgen
 
J

Jack Klein

Hey,

I was reading C99 Rationale, and it has the following two QUIET CHANGE
paragraphs:

6.5.3.4: "With the introduction of the long long and extended integer
types, the sizeof operator may yield a value that exceeds the range
of an unsigned long."

6.5.6: "With the introduction of the long long and extended integer
types, the subtraction of pointers may return a value that exceeds the
range of a long."

Was it required by C89 that result of sizeof() fits into unsigned long,
and that pointer subtraction result fits into long? If yes, then MS
Win64 implementation is not C89-conforming (while sizeof case may be
arguable, I guess, we certainly can ask to malloc more than ULONG_MAX
bytes, and get pointer arithmetics which needs more than (unsigned)
long). If no, why these two paragraphs, if programs which relied on long
being big enough were already broken?

Yevgen

What do you mean by "already broken"? Neither 64-bit Windows, nor the
AMD 64-bit extension to the x86 instruction set, existed before the
C99 standard.
 
Y

Yevgen Muntyan

Keith said:
Yevgen Muntyan said:
Eric Sosman wrote: [...]
I don't know MS' Win64 implementation well enough to comment
on whether it's broken or not.
It has 32-bit long, same as int, and naturally 64-bit size_t.

How is size_t defined? Does the implementation provide an "unsigned
long long" type and make size_t an alias for that? Or does it use
some non-standard syntax for its 64-bit types?

It doesn't have long long, it has builtin __int64, and

typedef __int64 intptr_t;
typedef unsigned __int64 uintptr_t;
typedef __int64 ptrdiff_t;
typedef unsigned __int64 size_t;

Yevgen
 
Y

Yevgen Muntyan

Jack said:
What do you mean by "already broken"? Neither 64-bit Windows, nor the
AMD 64-bit extension to the x86 instruction set, existed before the
C99 standard.

*If* Win64 is C90-conforming, then long smaller than size_t is fine,
then a program which uses unsigned long instead of size_t is broken
as far as C90 is concerned (of course it depends on the usage of
those types), so C99 doesn't need to say this is a quiet change.

Yevgen
 
S

Stephen Sprunk

Yevgen Muntyan said:
It claims conformance to C90. It does not conform to C99.

Win64 itself doesn't claim conformance with anything; since it's not a
complete implementation, it couldn't anyways. It's merely an API.

Individual compilers may or may not be compliant; I don't see how
an IL32LLP64 system could be C90-compliant , but it could be
C99-compliant. However, MSVC doesn't even attempt to be C99-
compliant. Since the _vast_ majority of code compiled with it is
blatantly unportable to any other implementation anyways, they can
get away with it. Another implementation for Win64 could be
C99-compliant if the authors wished.

(And for the record, MS wanted to do I32LP64, but they discovered that broke
nearly every program they tried to port, whereas IL32LLP64 allowed nearly
all of them to compile and work unchanged.)

S
 
R

Richard Bos

Yevgen Muntyan said:
You're saying it's legitimate.

Well, he says it's "legitimate". In this case, the scare quotes are
important. It's not more or less legal than other cases; but in this
case, it's inevitable, while in other cases, it can be avoided.
But how is casting size_t to unsigned long more legitimate than

int process_some_data (char *data, unsigned long len);

In this case, you could easily make len a size_t instead. Making it an
unsigned long instead is legal C90, but relying on this legality is
perhaps not a good idea, and making it a size_t means you get a
declaration which is more self-documenting for the cost, not of more,
but even of _less_ typing, which patently _is_ a good idea.

In the case of printf(), there's nothing you can easily do in C90 to
avoid having to cast a size_t to an unsigned long. C99 has "%zu", but
that's no help in C90, which does not.

Therefore, assuming a size_t is no larger than an unsigned long is
_legal_ in all cases in C90; but you only have _good reason_ for doing
so in the printf() case.

Richard
 
Y

Yevgen Muntyan

Richard said:
Well, he says it's "legitimate". In this case, the scare quotes are
important. It's not more or less legal than other cases; but in this
case, it's inevitable, while in other cases, it can be avoided.


In this case, you could easily make len a size_t instead.

*If* I can change the code. It's why I was confused: I can't imagine
why I would print a size_t value using unsigned long on Win64 platform,
but I can easily imagine how I use code which uses long instead
of ssize_t and unsigned long instead of size_t. Thanks for
clarification.
Making it an
unsigned long instead is legal C90, but relying on this legality is
perhaps not a good idea, and making it a size_t means you get a
declaration which is more self-documenting for the cost, not of more,
but even of _less_ typing, which patently _is_ a good idea.

By the way, it seems that some people avoid #includ'ing headers like
stddef.h in library headers due to bugs in C implementations
or for some other obscure reasons. I'd think it adds to this
issue: you can use long for free, it's builtin, but to get
size_t you need an extra header.

Yevgen
 
R

Richard Bos

Yevgen Muntyan said:
*If* I can change the code.

If _you_ can't change the code, I would advise not to worry about
whether the ideas expressed in it are legitimate or not; leave that to
the people who did design and do maintain it.
By the way, it seems that some people avoid #includ'ing headers like
stddef.h in library headers due to bugs in C implementations
or for some other obscure reasons. I'd think it adds to this
issue: you can use long for free, it's builtin, but to get
size_t you need an extra header.

Given that size_t is also #defined in <stdio.h>, <stdlib.h> and
<string.h>, probably the three most #included headers, without which I
can hardly imagine a useful ISO C program of any reasonable size, as
well as in <time.h> and <wchar.h>, IMO people who do this should do a
reality check.

Richard
 
Y

Yevgen Muntyan

Richard said:
If _you_ can't change the code, I would advise not to worry about
whether the ideas expressed in it are legitimate or not; leave that to
the people who did design and do maintain it.

That's good and everything, but doesn't always work on practice
unfortunately. If I happen to use some library which uses long instead
of ssize_t, and if I happen to get a dll of that library, I have a
problem. This Win64 thing is funny, because no other 'popular' system
has small long type. Good or bad, but lot of useful software is written
under many assumptions like 8-bit bytes, ASCII, long >= size_t. Simply
ignoring it won't always work since you might actually need that
software (you know, libraries which have useful stuff).
Given that size_t is also #defined in <stdio.h>, <stdlib.h> and
<string.h>, probably the three most #included headers, without which I
can hardly imagine a useful ISO C program of any reasonable size, as
well as in <time.h> and <wchar.h>, IMO people who do this should do a
reality check.

Perhaps. Or maybe it's because many vendors put lot of non-standard
stuff into standard headers. Say, if you #include <string.h> and
do not #define _GNU_SOURCE with glibc, then you don't get strndup()
declaration. But then library (not the C library) may not mandate
what you get and what you don't from the C library. So it would
need to document its headers include <string.h>, <foo.h>, and whatnot.
And then it must maintain that forever. Don't know, playing devil
advocate here.

Yevgen
 
E

Eric Sosman

Yevgen said:
That's good and everything, but doesn't always work on practice
unfortunately. If I happen to use some library which uses long instead
of ssize_t, and if I happen to get a dll of that library, I have a
problem.

Yes, indeed. Your problem is that you are using a library
written by somebody who didn't understand C, or who chose to be
deliberately perverse in the way he used it. When the library
writer is hostile or incompetent, you certainly have a problem.
This Win64 thing is funny, because no other 'popular' system
has small long type. Good or bad, but lot of useful software is written
under many assumptions like 8-bit bytes, ASCII, long >= size_t. Simply
ignoring it won't always work since you might actually need that
software (you know, libraries which have useful stuff).

Libraries that have useful stuff *and* for which no practical
alternatives exist *and* were written by incompetents or hostiles.

Do you have a specific library in mind, or are you "just
supposing?" If the latter, drop it until the situation actually
arises. If the former, please tell us about it so we'll be warned
not to use that organization's products.
Perhaps. Or maybe it's because many vendors put lot of non-standard
stuff into standard headers. Say, if you #include <string.h> and
do not #define _GNU_SOURCE with glibc, then you don't get strndup()
declaration. But then library (not the C library) may not mandate
what you get and what you don't from the C library. So it would
need to document its headers include <string.h>, <foo.h>, and whatnot.
And then it must maintain that forever. Don't know, playing devil
advocate here.

You're playing something, yes, but I don't recognize the tune.

Proposition: There is *no* reason to use unsigned long instead
of size_t. None. Nada. Zero. Zip. Nulla. Every module that
performs I/O includes <stdio.h> and has size_t defined; every
module that works with strings includes <string.h> and has size_t
defined; every module that calls malloc() includes <stdlib.h> and
has size_t defined. The definitions of size_t are so rampant in
the standard headers that it is almost as universal as a keyword.
The excuse "I don't want to include standard headers because they
might be broken" is hopelessly fallacious: If you don't trust the
headers, why would you trust the library? Do you provide a mian()
function just in case the implementation has a spelling error?

As for standard headers providing non-Standard definitions:
First, there are identifiers that are reserved for future use,
meaning that the standard headers are free to define them if
they so choose. You are not allowed to use `isosceles' as an
identifier with external linkage, and if you do use it you are at
fault and not the headers. Second, if you define reserved identifiers
like _GNU_SOURCE you invoke undefined behavior. You may *want* the
undefined behavior, but you can't ask the Standard to bless your
perverted desires. SAFUYOYO.
 
Y

Yevgen Muntyan

Eric said:
Yes, indeed. Your problem is that you are using a library
written by somebody who didn't understand C, or who chose to be
deliberately perverse in the way he used it. When the library
writer is hostile or incompetent, you certainly have a problem.

Well, I'd choose lighter words than "somebody who didn't
understand C" and "incompetent", but it won't change a thing of course.
Thing is: there is a problem which doesn't exist on sane systems
which use sensible types but which exists on Win64. Why it exists
is another problem.
Libraries that have useful stuff *and* for which no practical
alternatives exist *and* were written by incompetents or hostiles.

It's surely the easiest to walk a problem around by calling others
incompetent, especially if it's not your problem.
Do you have a specific library in mind, or are you "just
supposing?" If the latter, drop it until the situation actually
arises. If the former, please tell us about it so we'll be warned
not to use that organization's products.

I do have a specific library in mind, indeed. It's not written by me
or my friends or relatives. It's a widely used and indeed useful
library.
You're playing something, yes, but I don't recognize the tune.

Proposition: There is *no* reason to use unsigned long instead
of size_t. None. Nada. Zero. Zip. Nulla.

I know none, this is true. You seem to know none. You sure there
*isn't* one?
Every module that
performs I/O includes <stdio.h> and has size_t defined;

Unless this module use third-party I/O routines, or uses things like
open/write. I.e. no, not every.
every
module that works with strings includes <string.h> and has size_t
defined;

If it's C strings, then that's probably true.
every module that calls malloc() includes <stdlib.h> and
has size_t defined.

Yes, if a module calls malloc() then it needs to use stdlib.h. But
not every module calls malloc() to allocate memory. Some call
third-party routines which use unsigned long instead of size_t ;)

Anyway, these three examples are examples of why *user* would
use the standard headers. The library itself may not need them.
Now, it may be important for the user how he uses the standard
headers: what he #define's or in what order he uses the headers,
or whatever. Library has no business in that.
Now, if it's true that one single standard header ever caused
problems, then library developers have really good reason to avoid
standard headers altogether.
The excuse "I don't want to include standard headers because they
might be broken" is hopelessly fallacious: If you don't trust the
headers, why would you trust the library?

I, user, may know that on my FooBar-10.7 I need to sit then
jump three times to use some standard header; I can perform
those exercises when writing my program. If a library makes me a
"favor" and uses the header prior to my jumps, then it does a
wrong thing.

Somehow you started talking like I am saying "I don't want to
use standard headers in my program". Nope.
Do you provide a mian()
function just in case the implementation has a spelling error?

Ever heard of WinMain() thing? No, I don't provide mian() function.
I also don't eat spoons, and I don't fly.
As for standard headers providing non-Standard definitions:
First, there are identifiers that are reserved for future use,
meaning that the standard headers are free to define them if
they so choose. You are not allowed to use `isosceles' as an
identifier with external linkage, and if you do use it you are at
fault and not the headers.

Good or bad, but:

NAME
strdup, strndup, strdupa, strndupa - duplicate a string
SYNOPSIS
#define _GNU_SOURCE
#include <string.h>

char *strndup(const char *s, size_t n);

It's not (other) library developers business how user is going
to use strndup, it's personal matter between user and his C
library.
Second, if you define reserved identifiers
like _GNU_SOURCE you invoke undefined behavior. You may *want* the
undefined behavior,

See above, SYNOPSIS section.
but you can't ask the Standard to bless your
perverted desires. SAFUYOYO.

Am I asking the standard about something?

Yevgen
 
Y

Yevgen Muntyan

Eric said:
Yes, indeed. Your problem is that you are using a library
written by somebody who didn't understand C, or who chose to be
deliberately perverse in the way he used it. When the library
writer is hostile or incompetent, you certainly have a problem.

Forgot to mention another evil thing the library does: it uses void*
for function pointers. I wonder if it's caused by hostility or
incompetence.
 
E

Eric Sosman

Yevgen said:
I do have a specific library in mind, indeed. It's not written by me
or my friends or relatives. It's a widely used and indeed useful
library.

... which you have not named, to warn us away from it.
I know none, this is true. You seem to know none. You sure there
*isn't* one?

I offered the remark as a "proposition," thus inviting
a counter-example. Got one?
Unless this module use third-party I/O routines, or uses things like
open/write. I.e. no, not every.

Yes, "every" -- unless you've decided to stray outside the
bounds of Standard C. There are good reasons for such strayings,
but you can hardly blame the consequences on the Standard headers.
Anyway, these three examples are examples of why *user* would
use the standard headers. The library itself may not need them.
Now, it may be important for the user how he uses the standard
headers: what he #define's or in what order he uses the headers,
or whatever. Library has no business in that.

Again, I'd be interested to learn the name of this perverse
library you keep alluding to.

Proposition: A library that deals in object sizes but uses
unsigned long instead of size_t to describe them is perverse.
Counter-example?
Now, if it's true that one single standard header ever caused
problems, then library developers have really good reason to avoid
standard headers altogether.

Balderdash. They should be equally leery of the % operator.
Somehow you started talking like I am saying "I don't want to
use standard headers in my program". Nope.

Your argument (perhaps I have misunderstood it) was that
someone might prefer to use unsigned long instead of size_t
because he would need to include a Standard header to obtain
a size_t definition, and the implementation's headers might
be broken. That's what I think you said; that's what I reject.
Ever heard of WinMain() thing? No, I don't provide mian() function.
I also don't eat spoons, and I don't fly.

Yes, I've heard of the WinMain() thing. It's perfectly legal,
but only for free-standing (not hosted) environments. In those
systems, the entire Standard library is optional and you cannot
even rely on the existence of exit(). Those systems do not meet
the requirements the Standard places on hosted systems, and if
they claim to conform to the Standard for hosted systems they
claim incorrectly.
Good or bad, but:

NAME
strdup, strndup, strdupa, strndupa - duplicate a string
SYNOPSIS
#define _GNU_SOURCE
#include <string.h>

char *strndup(const char *s, size_t n);

It's not (other) library developers business how user is going
to use strndup, it's personal matter between user and his C
library.

Um, er, haven't you simply illustrated what I wrote? "There
are identifiers that are reserved for future use, meaning that
the standard headers are free to define them." The four strxxx()
identifiers you show are in that class: The implementation is at
liberty to provide them, and if you use `strdup' or `streptomycin'
as an identifier, the clash is your fault, not the implementation's.
"Personal matters" have nothing to do with it: You either tread on
the reserved name space and risk the consequences, or you keep your
distance and remain safe.

The situation is a little tenser if you decide to call upon
strdup() -- or stromboli() -- in your program. The implementation
is permitted to define these identifiers, but is not obliged to do
so and is not obliged to give them any specific meaning. Perhaps
strdup() duplicates a string, but as far as the Standard is concerned
it might just as well cause chocolate pudding to ooze from your
keyboard. *That* might be a "personal matter" between the user and
the C implementation, in the same way that simply assuming a 27-bit
int is a "personal matter."
See above, SYNOPSIS section.

As I said, you may want the undefined behavior. That's
one of those "personal matters" you refer to, but not a problem
for C. You're out in the unexplored and exciting territory --
not necessarily a bad place to be, but not a country where the
laws are universally obeyed. Or even understood. If you want
to deal with Roy Bean, "The Hangin' Judge," "The Law West of
the Pecos," that's your lookout. It has its rewards, but also
its dangers.
 

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