C (functional programming) VS C++ (object oriented programming)

A

Al Balmer

But so few programmers understand that.

Oh, nonsense. I'm getting tired of this. It seems to me that you
either have experience with a very limited (and incompetent) group of
programmers, or are projecting your own assumptions to the universe.
 
R

Richard Weeks

Charlie said:
This newsgroup is read by a lot of programmers with varying degrees of
skill. The more become aware of strncpy's woes, the less likely they will
be producing buggy code using it.

For the edification a programmer (myself) with varying degrees of
skill, what exactly are strncpy's "woes?"

RW
 
M

Malcolm McLean

Tor Rustad said:
With the latest VC++, I couldn't figure how to create a simple console C
project, without those C++ files being generated. :-(

So, I still use VC++ 6, when possible.. less bloated and no *_s warnings.
You fiddle with it. It doesn't want to create a .c file unless you force it
to. Then you need to fiddle with settings even more to prevent it adding an
stdafx file and refusing to compile anything that won't include it. Finally
you can turn off the warnings that deprecate printf().
However it isn't the real answer. I want other people to be able to compile
my code cleanly and to incorporate functions intko their own projects.
 
T

Tor Rustad

Richard said:
Tor Rustad said:
Richard Heathfield wrote:
[...]
Fixing the disease for one patient, doesn't lead to a healthy world.

It does, however, lead to a healthier patient.
The smarter method, is to use simpler & better interfaces. For those
interested, look up the paper "strlcpy and strlcat -- consistent, safe,
string copy and concatenation."

You lost me completely. What have they to do with our discussion about
strncpy?


Thought my view on the matter was crystal clear, just like it was *6
years* ago. Nothing has changed!!! :)


Richard Heathfield, are you an Ulrich Drepper fanboy, or what?
 
T

Tor Rustad

Al said:
Al said:
On Tue, 02 Oct 2007 22:47:19 +0200, Tor Rustad

Al Balmer wrote:
[...]


Even GCC decided not to add it :)
Did you follow the GNU discussion back then? IIRC, the main argument
against it, was that few C programmers, demanded these functions and
that rolling your own would be easy.
Only sporadically, since I didn't have any strong feelings either way.
I remember claims that there was no evidence that they made things
safer, despite their long history in BSD,
IMO, security wise, OpenBSD track record is rather good. OpenBSD homepage:

"Only two remote holes in the default install, in more than 10 years!"

I'm only recalling the argument. Of course, the fact that BSD is
relatively secure is not necessarily due to the use of strlcpy.

This might have been discussed multiple times by the glibc people then.
The strl* functions was invented to fix the OpenBSD sources:

"We found a large number of overflows due to unbounded string copies
using sprintf(), strcpy() and strcat(), as well as loops that
manipulated strings without an explicit length check in the loop
invariant. Additionally, we also found many instances where the
programmer had tried to do safe string manipulation with strncpy() and
strncat() but failed to grasp the subtleties of the API."
- Miller & Raadt

suggesting this initiative made no difference... is rather far fetched.

It has nothing to do with the library, but with the people using it.


? truncation is a *feature* of the current implementation. If
truncation is an error meriting an assert, it seems to me that prior
detection of the situation and a call to strcpy or strncpy would be
better. I'm probably missing something.

I don't consider truncation a feature at all, but rather way to
implement run-time recovery.

If destination buffer doesn't have the required size to hold all the
data, it's typically a programming fault, and silencing such a thing, is
IMO not the way solid code should be.
 
M

Malcolm McLean

Richard Heathfield said:
Charlie Gordon said:


Absolutely right. Same applies to motor vehicles, kitchen knives, and
indeed any other potentially dangerous tool that can be misused by humans.
So what do you want people to do - go back to the Stone Age? Or maybe -
just maybe - they can learn how to use tools properly?
We've got a chocolate machine at Leeds which takes the number of the product
you are buying. Numbers go from about 1-100. Next to the number is displayed
the price, typically around 50p.

It is of course a atrocious design because it is so easy to enter a price
rather than an id, and end up buying the wrong thing. However after six
years I do have the hang of it. It is possible to use the machine correctly,
if you are careful.

Similarly with strncpy(). Anyone would think it is strcpy() with an extra
knob on. It is terrible design, unfortunately not easy to fix once millions
of ,lines of code have been written which call it.
 
R

Richard Heathfield

Richard Weeks said:
For the edification a programmer (myself) with varying degrees of
skill, what exactly are strncpy's "woes?"

Let's start by clarifying exactly what strncpy does. Here is the C89 text:

Synopsis

#include <string.h>
char *strncpy(char *s1, const char *s2, size_t n);

Description

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 ./120/ If copying takes place
between objects that overlap, the behavior is undefined.

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.

Returns

The strncpy function returns the value of s1 .


Okay, the first thing to notice is that, along with strncmp (and, not very
interestingly, strerror), strncpy does not require any of its parameters
to represent strings. All the other str* functions declared in <string.h>
do, but strncpy and strncmp do not.

Because of this, it can reasonably be argued that they have lousy names.
Well, I agree - they do. And those are strncpy's and strncmp's woes,
basically.

The real woe lies not in the functions themselves, but in the way that they
are used. The strncpy function is often recommended, by people who ought
to know better, as a "safe" version of strcpy:

#define N 6
char target[N] = "";
strncpy(target, source, sizeof target - 1);

or perhaps

#define N 6
char target[N];
strncpy(target, source, sizeof target);
target[N - 1] = '\0';

They reason that it's better to lose some data than to invoke undefined
behaviour. Well, so it is - but just because invoking UB is wrong, that
doesn't mean that losing data is right!

That is not what strncpy is for.

It is for copying substrings, fields, call them what you like, from one
block of memory to another. The null padding is a bit of a canard, really.

Here is an example of a *good* use of strncpy (which is otherwise not
terribly well-written, but I've tried to make it as clear as possible):

char date[25] = "";
char *d = asctime(&tmstruct);
strncpy(date, d + 11, 9); /* hh:mm:ss */
strncpy(date + 9, d, 4); /* nnn */
strncpy(date + 9 + 4, d + 8, 3); /* dd */
strncpy(date + 9 + 4 + 3, d + 4, 4); /* mmm */
strncpy(date + 9 + 4 + 3 + 4, d + 20, 4); /* yyyy */

That's what it's for - building a record a piece at a time by copying data
from a record-like (multiple field) source.

And it does that job perfectly well.
 
M

Malcolm McLean

Richard Weeks said:
For the edification a programmer (myself) with varying degrees of skill,
what exactly are strncpy's "woes?"
/*
Evil, buggy code. Don't do this at home kids.
*/

char buff[32];

strncpy(buff, argv[1], 32);
printf("Your string was %s\n", buff);

/*
This is just as bad in its way, but not an error
*/
char buff[1024];

char *bottleneck = "a string in an inner loop";

strncpy(buff, bottleneck, 1023);
buff[1023] = 0;
 
B

Ben Pfaff

Richard Weeks said:
For the edification a programmer (myself) with varying degrees of
skill, what exactly are strncpy's "woes?"

There is occasionally a good reason to use strncpy(). However:

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

* 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.
 
K

Keith Thompson

Richard Heathfield said:
Charlie Gordon said:

This is very, very simple to understand, and programming is a highly
complex activity requiring considerable intelligence to do properly.
Anyone not capable of understanding that strncpy is not supposed to be
used as a "safe string copy" has no business being a programmer. If you
find such people in your place of work, fire them. They'd be far happier
in marketing, anyway.

There's a big difference between not understanding something and not
being capable of understanding something. Plenty of people don't know
how strncpy() actually works, but are more than capable of
understanding it once it's explained.

Intercal, if I recall correctly, uses WRITE for input and READ for
output. You need to understand that in order to use the language
properly, but someone new to the language can hardly be blamed for
assuming that WRITE performs output and READ performs input. (That's
not a great example, since Intercal was specifically designed to be
counter-intuitive.)

A well designed language or library should follow the principle of
least surprise as much as possible (but no more than possible).
strncpy() violates that principle. Its use or misuse is ultimately
the responsibility of each programmer, but it's partly the fault of
its misleading name. (There's no shortage of blame to go around.) My
example earlier in this thread was a print_line() function that does
something other than printing a line.

Also, the data format supported by strncpy() is unusual enough that,
if you ignore the historical context of Unix directory structures,
it's quite surprising that the standard library directly supports it.
There are any number of things that *could* have been included in the
standard library (strdup() is one whose lack surprises a lot of
people); the decision to include strncpy() was an odd one.

The real lesson: assuming that the C standard library is a consistent
and coherently designed interface is dangerous. It isn't. Once you
understand that, you'll probably be ok.
 
A

Al Balmer

That's what it's for - building a record a piece at a time by copying data
from a record-like (multiple field) source.

I have another use that it fits nicely, but is rather specialized. We
use a database which defines fixed-length "strings." The strings are
terminated either by the end of the field, or by a null. strncpy works
very nicely when filling these fields.
 
F

Flash Gordon

Malcolm McLean wrote, On 03/10/07 21:07:
You fiddle with it. It doesn't want to create a .c file unless you force
it to. Then you need to fiddle with settings even more to prevent it
adding an stdafx file and refusing to compile anything that won't
include it. Finally you can turn off the warnings that deprecate printf().

Or you do it once and set those as your defaults. Or you do it once
setting up a "template" that you use for future projects. Or you work
out how to drive it from the command line to "do the right thing" once
and create a script for building "projects". Or the first time you write
down how to do it and then you follow your notes on subsequent
occasions, so no "fiddling" required. Or...
However it isn't the real answer. I want other people to be able to
compile my code cleanly and to incorporate functions intko their own
projects.

Give them pre-compiled code. Or give them a "project file" that is
correctly set up. Or give them a script for doing the building that does
the right things. Or use any of the other systems that people use
whatever their target is.

Note that in "script" in include MS batch files, makefiles for all
versions of make, nmake etc, bash scripts, javascript and whatever other
methods people have come up with for scripting builds. There are plenty
to choose from that work on Windows with Visual Studio.
 
F

Flash Gordon

Malcolm McLean wrote, On 03/10/07 21:15:
We've got a chocolate machine at Leeds which takes the number of the
product you are buying. Numbers go from about 1-100. Next to the number
is displayed the price, typically around 50p.

It is of course a atrocious design because it is so easy to enter a
price rather than an id, and end up buying the wrong thing.

Never happened to me even as a child using machines of this type in the 70s.
However
after six years I do have the hang of it.

It took you six years? I really do find that amazing.
It is possible to use the
machine correctly, if you are careful.

I never had to be careful. After all, you have to read both numbers
anyway so that you know how much they will charge you before selecting
your purchase.
Similarly with strncpy(). Anyone would think it is strcpy() with an
extra knob on. It is terrible design, unfortunately not easy to fix once
millions of ,lines of code have been written which call it.

It is perfectly designed for the job it is intended to do, it is just a
terrible and misleading name for a function with that job.
 
F

Flash Gordon

Tor Rustad wrote, On 03/10/07 21:14:
I don't consider truncation a feature at all, but rather way to
implement run-time recovery.

If destination buffer doesn't have the required size to hold all the
data, it's typically a programming fault, and silencing such a thing, is
IMO not the way solid code should be.

Imagine a program where a user can specify how large a "data block" is.
Then imagine if the user can specify a string to be stored in that "data
block". Then imagine if the *requirement* is to truncate strings which
are too long, possibly with a requirement to produce a warning. Some
programs *do* have these requirements, and for such a program truncation
by the library function used to do the copying would not indicate an
error in the program, it would be the program making use of the way the
function is designed to achieve the requirements. Some database type
programs can have such requirements and there are other situations where
there are requirements to copy and if required truncate a string.
 
J

jacob navia

Keith Thompson wrote:
[snip]
The real lesson: assuming that the C standard library is a consistent
and coherently designed interface is dangerous. It isn't. Once you
understand that, you'll probably be ok.

But isn't that acknowledging that this part of the language
needs reworking?

Those _s functions like fopen_s and others proposed in that
Technical Report are a start isn't it?
 
A

Al Balmer

Or you do it once and set those as your defaults. Or you do it once
setting up a "template" that you use for future projects. Or you work
out how to drive it from the command line to "do the right thing" once
and create a script for building "projects". Or the first time you write
down how to do it and then you follow your notes on subsequent
occasions, so no "fiddling" required. Or...

Viva la makefile!
 
T

Tor Rustad

Flash said:
Tor Rustad wrote, On 03/10/07 21:14:

Imagine a program where a user can specify how large a "data block" is.
Then imagine if the user can specify a string to be stored in that "data
block". Then imagine if the *requirement* is to truncate strings which
are too long, possibly with a requirement to produce a warning. Some
programs *do* have these requirements, and for such a program truncation
by the library function used to do the copying would not indicate an
error in the program, it would be the program making use of the way the
function is designed to achieve the requirements. Some database type
programs can have such requirements and there are other situations where
there are requirements to copy and if required truncate a string.

The problem isn't that I can't imagine such a usage, but that this use
case is rather a typical programming *fault*. So, I deliberately put the
assert() in there, to catch it.


For the special case you describe, I would rather write something like:

n = sprintf(dest, "%.*s", max, src);
 
T

Tor Rustad

Richard said:
Tor Rustad said:



Never heard of him/her/it.

Drepper was the GNU man that rejected adding strl*.

Raadt wasn't very pleased about that descision. :)
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top