supplementary C frequent answers

B

Ben Pfaff

Over the last couple of years, and especially recently, I've
built up a few "stock" answers that supplement the C FAQ. If
anyone wants to review and comment on them, I've just now put
them up on my webpage, at
http://benpfaff.org/writings/clc
 
P

Peter Pichler

Ben Pfaff said:
Over the last couple of years, and especially recently, I've
built up a few "stock" answers that supplement the C FAQ. If
anyone wants to review and comment on them, I've just now put
them up on my webpage, at
http://benpfaff.org/writings/clc

From that website:
"Using strncpy() into a large buffer can be very inefficient. strncpy()
always
writes to every byte in the destination buffer, which can waste a lot of
time
if the destination buffer is much longer than the source string."

Isn't this a QoI issue? According to the Standard,

"The strncpy function copies not more than n characters (characters that
follow a null character are not copied) from the array pointed to by s2 to
the array pointed to by s1. If copying takes place between objects that
overlap, the behavior is undefined."

Please note the part in parenteses.

Also from your website,

"If the source string is longer than the size of the destination buffer,
then strncpy() doesn't write a terminating null. So a call to strncpy() must
be
followed by explicitly writing a null terminator at the end of the
destination
buffer in most cases."

Nothing simpler:

strncpy(dest, src, n)[n-1] = 0;

IMNSHO, strncpy() is far more advisable than strcpy().

Lastly, "off-topic guidance message" is a good title in a context of a
specific thread. As a general guidance, as e.g. on your website, it will
most likely go unnoticed ("I never write off-topic posts, why should I waste
my time reading it?").
Something like "comp.lang.c topicality guidance" might be better. Just my
£0.02.

Peter
 
R

Richard Heathfield

Peter said:
From that website:
"Using strncpy() into a large buffer can be very
inefficient. strncpy() always writes to every byte
in the destination buffer, which can waste a lot of
time if the destination buffer is much longer than
the source string."

Isn't this a QoI issue?
No.

According to the Standard,

"The strncpy function copies not more than n characters (characters that
follow a null character are not copied) from the array pointed to by s2 to
the array pointed to by s1. If copying takes place between objects that
overlap, the behavior is undefined."

Please note the part in parenteses.

Please note the very next sentence: "If the array pointed to by s2 is a
string that is shorter than n characters, null characters are appended to
the copy in the array pointed to by s1, until n characters in all have been
written."
Also from your website,

"If the source string is longer than the size of the destination buffer,
then strncpy() doesn't write a terminating null. So a call to strncpy()
must be followed by explicitly writing a null terminator at the end of the
destination buffer in most cases."

Nothing simpler:

strncpy(dest, src, n)[n-1] = 0;

Easy to forget to do that, though, and it assumes that dest is at least n
bytes long, which it might not be.
IMNSHO, strncpy() is far more advisable than strcpy().

That's like saying a screwdriver is more advisable than a hammer. It depends
on what you're trying to do. strncpy's job is to copy part of a string,
whereas strcpy's job is to copy a whole string. It is silly to use strncpy
if your objective is to copy the whole string.
Lastly, "off-topic guidance message" is a good title in a context of a
specific thread. As a general guidance, as e.g. on your website, it will
most likely go unnoticed ("I never write off-topic posts, why should I
waste my time reading it?").
Something like "comp.lang.c topicality guidance" might be better. Just my
£0.02.

Better, and it suggested "Guidance on finding the best newsgroup for your
question" to me as a (rather verbose but otherwise perhaps more friendly)
possibility.
 
P

pete

Peter said:
From that website:
"Using strncpy() into a large buffer can be
very inefficient. strncpy() always writes to every byte in the
destination buffer, which can waste a lot of time
if the destination buffer is much longer than the source string."

Isn't this a QoI issue?

If you strncpy a zero length string source to
a hundred byte length string destination,
101 bytes of the destination string will be overwritten.

If you strcpy a zero length string source to
a hundred byte length string destination,
1 byte of the destination string will be overwritten.
 
J

Jeremy Yallop

Richard said:
Peter said:
"If the source string is longer than the size of the destination buffer,
then strncpy() doesn't write a terminating null. So a call to strncpy()
must be followed by explicitly writing a null terminator at the end of the
destination buffer in most cases."

Nothing simpler:

strncpy(dest, src, n)[n-1] = 0;

Easy to forget to do that, though, and it assumes that dest is at least n
bytes long, which it might not be.

If dest is less than n bytes long then the call to strncpy() is broken
already.

Jeremy.
 
P

Peter Pichler

Richard Heathfield said:
Peter Pichler wrote:
(about strncpy() being inefiicient)
No.

Please note the very next sentence: "If the array pointed to by s2 is a
string that is shorter than n characters, null characters are appended to
the copy in the array pointed to by s1, until n characters in all have been
written."

Doh! Richard, was it you running the reading for comprehension course? Where
can I enroll?
That's like saying a screwdriver is more advisable than a hammer. It depends
on what you're trying to do. strncpy's job is to copy part of a string,
whereas strcpy's job is to copy a whole string. It is silly to use strncpy
if your objective is to copy the whole string.

In many cases, you don't know how long the source string is. If I should
call strlen() first to find out, I could just as well use strncpy().

Peter
 
J

Jeremy Yallop

Ben said:
Over the last couple of years, and especially recently, I've
built up a few "stock" answers that supplement the C FAQ. If
anyone wants to review and comment on them, I've just now put
them up on my webpage, at
http://benpfaff.org/writings/clc

| When are casts appropriate?
|
| Casts are generally undesirable, but there are several situations
| where a cast legitimately comes in handy:
[...]
| * Passing a null pointer to a varargs function.

More generally, calling a varargs function with any value whose type
isn't compatible with what the function expects.

Jeremy.
 
L

Lowell Gilbert

[Somebody] said
That's a slightly limited way of looking at it; you could also say
that strncpy's "job" is to copy all of a string up to a limit. Having
that limit be within the target buffer's boundaries can be useful.

Peter Pichler said:
In many cases, you don't know how long the source string is. If I should
call strlen() first to find out, I could just as well use strncpy().

All else being equal. In practice, I often find that the length may
be needed for other reasons. I wouldn't bother making this point to a
beginner, though.
 
R

Richard Heathfield

Peter Pichler wrote:

In many cases, you don't know how long the source string is. If I should
call strlen() first to find out, I could just as well use strncpy().

Um, I think you really *should* sign up for that course, Peter. :)

If you need the whole string, you simply *have* to know how much storage
you'll need if you want to make a copy of it, and you *must* have the right
amount of storage available.

Having ascertained that "this" will fit into "that", by all means call
strncpy instead of strncpy if you really like typing all that much, but it
adds no extra safety and does not communicate your intent as well as strcpy
does.
 
P

Peter Pichler

Richard Heathfield said:
Um, I think you really *should* sign up for that course, Peter. :)

("that" being "reading for comprehension", just for the benefit of innocent
bystanders)

No doubt ;-)
If you need the whole string, you simply *have* to know how much storage
you'll need if you want to make a copy of it, and you *must* have the right
amount of storage available.

Perhaps we both need the course ;-) What if I don't care about the /whole/
string, but need to limit how much to copy because I know the length of the
destination buffer and know that it may not be long enough? Strange as it
may seem, I have just recently appeared in exactly that situation. To be
fair, I did not realize that strncpy() filled up the remaining space with
zeros. <eom>

Peter
 
J

Joe Wright

pete said:
If you strncpy a zero length string source to
a hundred byte length string destination,
101 bytes of the destination string will be overwritten.
Show me. strncpy() will write n characters to the destination.
 
R

Richard Heathfield

Peter said:
What if I don't care about the /whole/
string, but need to limit how much to copy because I know the length of
the destination buffer and know that it may not be long enough?

If you don't care about the whole string, strcpy is the Wrong Thing for that
task, because strcpy /does/ copy the whole string.

Personally, I never use strncpy. If I care about the whole string, I make
sure the receiving buffer is big enough. If I don't care about the whole
string, I don't treat it /as/ a string (since the bit that I care about
/isn't/ a string), and I would favour mem* routines rather than str*
routines for that purpose.
 
B

Ben Pfaff

Jeremy Yallop said:
Ben said:
Over the last couple of years, and especially recently, I've
built up a few "stock" answers that supplement the C FAQ. If
anyone wants to review and comment on them, I've just now put
them up on my webpage, at
http://benpfaff.org/writings/clc

| When are casts appropriate?
|
| Casts are generally undesirable, but there are several situations
| where a cast legitimately comes in handy:
[...]
| * Passing a null pointer to a varargs function.

More generally, calling a varargs function with any value whose type
isn't compatible with what the function expects.

Most of the time, though, such conversions are more reasonably
done without a cast. (In my opinion, of course.)
 
S

Servé Lau

Ben Pfaff said:
Over the last couple of years, and especially recently, I've
built up a few "stock" answers that supplement the C FAQ. If
anyone wants to review and comment on them, I've just now put
them up on my webpage, at
http://benpfaff.org/writings/clc

IMO, the article "why should toupper()'s argument be cast to unsigned char?"
is not explained very well.
What do you mean with "If char is signed, then some characters have negative
values". It could use an example.

I'd also elaborate about the valid return values from main in the article
"how should main be declared". Maybe the difference between implicit return
values in C89 and C99 would fit in there too (or put it in another article)

The article about malloc's return value could use an example for its third
point. "If you cast to the wrong type by accident, odd failures can result"
What odd failures? Convince me.
 
K

Keith Thompson

Ben Pfaff said:
Jeremy Yallop said:
Ben said:
Over the last couple of years, and especially recently, I've
built up a few "stock" answers that supplement the C FAQ. If
anyone wants to review and comment on them, I've just now put
them up on my webpage, at
http://benpfaff.org/writings/clc

| When are casts appropriate?
|
| Casts are generally undesirable, but there are several situations
| where a cast legitimately comes in handy:
[...]
| * Passing a null pointer to a varargs function.

More generally, calling a varargs function with any value whose type
isn't compatible with what the function expects.

Most of the time, though, such conversions are more reasonably
done without a cast. (In my opinion, of course.)

Can you give some examples?

Here are a couple of cases where (IMHO) a cast is appropriate:

int *ptr = <whatever>;

printf("sizeof(ptr) = %d\n", (int)sizeof(ptr));
printf("ptr = [%p]\n", (void*)ptr);

In C99, you can avoid the cast in the first printf by using "%zu", but
that's not universally supported yet. (I might use unsigned long
rather than int, but I'm reasonably certain in this case that
sizeof(ptr) <= INT_MAX.)

In the second printf, I don't see a good way to avoid the cast.
 
B

Ben Pfaff

Servé Lau said:
IMO, the article "why should toupper()'s argument be cast to unsigned char?"
is not explained very well.
What do you mean with "If char is signed, then some characters have negative
values". It could use an example.

Okay, I've updated it. (Changes may take a minute or two to
propagate.)
I'd also elaborate about the valid return values from main in the article
"how should main be declared". Maybe the difference between implicit return
values in C89 and C99 would fit in there too (or put it in another article)

Sure, good suggestion.
The article about malloc's return value could use an example for its third
point. "If you cast to the wrong type by accident, odd failures can result"
What odd failures? Convince me.

I don't recall at the moment, but it's definitely true--I've seen
them. Alignment-related failures surely, and I think there are
others.
 
R

Richard Heathfield

Ben said:
I don't recall at the moment, but it's definitely true--I've seen
them. Alignment-related failures surely, and I think there are
others.

Consider a C90 implementation which stores returned pointers in one
register, and returned integers in another. If you forget to provide a
correct prototype for a function returning a pointer, such as malloc, the
implementation is obliged to assume that the function in question returns
int, rather than a pointer type, and therefore your code could receive a
garbage value from the integer register rather than the value that malloc
actually returns, which the implementation correctly stores in the pointer
register.
 
B

Ben Pfaff

Richard Heathfield said:
Consider a C90 implementation which stores returned pointers in one
register, and returned integers in another. If you forget to provide a
correct prototype for a function returning a pointer, such as malloc, the
implementation is obliged to assume that the function in question returns
int, rather than a pointer type, and therefore your code could receive a
garbage value from the integer register rather than the value that malloc
actually returns, which the implementation correctly stores in the pointer
register.

Such a problem would be covered by the second point, "Casting its
return value can mask a failure to #include <stdlib.h>, which
leads to undefined behavior." We are discussing the third point,
"If you cast to the wrong type by accident, odd failures can
result."
 
P

Peter Pichler

Richard Heathfield said:
Ben said:
I don't recall at the moment, but it's definitely true--I've seen
them. Alignment-related failures surely, and I think there are
others.

Consider a C90 implementation which stores returned pointers in one
register, and returned integers in another. If you forget to provide a
correct prototype for a function returning a pointer, such as malloc [...]

With more missing context in this message, I thought that he was talking
about /having/ a prototype yet casting to the wrong type. Can you see any
problems with that other than failing to compile?
 
R

Richard Heathfield

Ben Pfaff wrote:

Such a problem would be covered by the second point, "Casting its
return value can mask a failure to #include <stdlib.h>, which
leads to undefined behavior." We are discussing the third point,
"If you cast to the wrong type by accident, odd failures can
result."

Oops. Sorry about that.
 

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,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top