Who has actually used a variadic function for any purpose other than implementing printf-style format strings?
Who has actually used a variadic function for any purpose other than implementing printf-style format strings?
Who has actually used a variadic function for any purpose other than implementing printf-style format strings?
Who has actually used a variadic function for any purpose other than implementing printf-style format strings?
On 20/01/2024 16:52, Spiros Bousbouras wrote:
On Sat, 20 Jan 2024 11:19:57 +0000I've sometimes written a "cat" function. But I always write it to take
Malcolm McLean <malcolm.arthur.mclean@gmail.com> wrote:
Yes. It seems there are a few libraries that also use variadic
arguments. I tend not to do that sort of programming and I'm not very
familar with them.
But no-one has yet come up with an occasion where they implemented a
variadic function by choice, for code which they controlled, except for
printf style formatting. Either a hobby project or work code for which
they had ownership.
I asked a similar question on this group many years ago. One example
given
was a function for concatenating strings which would accept as
arguments a
variable number of strings.
two strings. However I don't do much text processing.
But no-one has yet come up with an occasion where they implemented a
variadic function by choice, for code which they controlled ...
On 20/01/2024 21:37, Lawrence D'Oliveiro wrote:
On Sat, 20 Jan 2024 11:19:57 +0000, Malcolm McLean wrote:
But no-one has yet come up with an occasion where they implemented a
variadic function by choice, for code which they controlled ...
But the people who created these libraries we mentioned certainly did.
I was wrong. As was pointed out eslewhere. Kaz gave some examples. But
his first was of usage.
Of course someone must have taken the decision that the call to evoke an external process would take a variable list of arguments rather than a
single string. However In find that, of thousands of functions in my
code base, not a single one is variadic except a few interfaces to
vsprintf.
Of course someone must have taken the decision that the call to evoke an external process would take a variable list of arguments rather than a
single string.
Who has actually used a variadic function for any purpose other than implementing printf-style format strings?
Of course someone must have taken the decision that the call to evoke an external process would take a variable list of arguments rather than a
single string. However In find that, of thousands of functions in my
code base, not a single one is variadic except a few interfaces to
vsprintf.
On Sat, 20 Jan 2024 22:37:48 +0000, Malcolm McLean wrote:
Of course someone must have taken the decision that the call to evoke an
external process would take a variable list of arguments rather than a
single string. However In find that, of thousands of functions in my
code base, not a single one is variadic except a few interfaces to
vsprintf.
I have the urge to implement one, purely to provide a counterexample. As
an excuse, I will use it to demonstrate a technique for typesafely calling such a function from Python code via ctypes.
But no-one has yet come up with an occasion where they implemented a
variadic function by choice, for code which they controlled ...
On Sat, 20 Jan 2024 11:19:57 +0000, Malcolm McLean wrote:
But no-one has yet come up with an occasion where they implemented a
variadic function by choice, for code which they controlled ...
OK, I have done one. Just a simple one, to demonstrate how to make
typesafe calls to it via a Python wrapper. It’s part of my “Python Topics Notebooks” collection <https://gitlab.com/ldo/python_topics_notebooks/>. The C code (stack_calc.[ch]) is a very basic RPN calculator, which takes a varargs list of operators (integer) and operands (real), and returns the final calculated result.
The notebook that makes use of it is called “ctypes Tip Extra -- Calling A Variadic Function”.
On 20/01/2024 23:02, bart wrote:
On 20/01/2024 22:37, Malcolm McLean wrote:I have occasionally passed the wrong type to printf. Usually a long
On 20/01/2024 21:37, Lawrence D'Oliveiro wrote:
On Sat, 20 Jan 2024 11:19:57 +0000, Malcolm McLean wrote:I was wrong. As was pointed out eslewhere. Kaz gave some examples.
But no-one has yet come up with an occasion where they implemented a >>>>> variadic function by choice, for code which they controlled ...
But the people who created these libraries we mentioned certainly did.
;
But his first was of usage.
Of course someone must have taken the decision that the call to evoke
an external process would take a variable list of arguments rather
than a single string. However In find that, of thousands of functions
in my code base, not a single one is variadic except a few interfaces
to vsprintf.
Variadic functions were likely added to implement *printf functions,
since the language didn't want to make special provision just for those.
Then a number of people decided to make use of the feature, although
less often than you might expect.
But it is not a desirable feature for general use as it is not type-safe.
The other thing is, calling a variadic function is a lot easier than
writing the body of one. That will likely put many off.
I wouldn't be able to do it without looking up some examples.
integer to %d. But I can't recall an occasion where the problem wasn't quickly fixed. Xcode gives a warning for mismatched format string
parameters, but of course it can't do that for roll your own.
The other thing is passing a raw pointer to %p instead of casting to
void *. Technically this is an error, but %p is only really useful for temporary debug code, so it's just pointless typing to out the cast in.
Variardic functions are implemented with macros and it's a bit hard to
work out what is going on. But it's not that hard. I don't think it's a
good reason for avoiding them. On the other hand, I implemented a C++ variable length template expansion to produce a "simple JSON" which is
in effect a varidaic function with type information. But whilst I
implemented it myself, I can't remember exactly how it is supposed to
work or what the syntax means.
On Sun, 21 Jan 2024 13:27:30 +0000, bart wrote:
That is, the user-code in Python doesn't directly call 'stack_calc'.
This means that there is no real need for the C function to be variadic.
It could take a single pointer to any arbitrary C data structure that
can represent your sample expression. Or maybe two pointers to parallel
arrays. Or ...
... and be just as type-unsafe as the variadic option.
That is, the user-code in Python doesn't directly call 'stack_calc'.
This means that there is no real need for the C function to be variadic.
It could take a single pointer to any arbitrary C data structure that
can represent your sample expression. Or maybe two pointers to parallel arrays. Or ...
On 21/01/2024 21:29, Lawrence D'Oliveiro wrote:variadic.
On Sun, 21 Jan 2024 13:27:30 +0000, bart wrote:
That is, the user-code in Python doesn't directly call 'stack_calc'.
This means that there is no real need for the C function to be
parallel
It could take a single pointer to any arbitrary C data structure that
can represent your sample expression. Or maybe two pointers to
arrays. Or ...
... and be just as type-unsafe as the variadic option.
No, it wouldn't.
On Sun, 21 Jan 2024 21:43:13 +0000, bart wrote:
On 21/01/2024 21:29, Lawrence D'Oliveiro wrote:variadic.
On Sun, 21 Jan 2024 13:27:30 +0000, bart wrote:
That is, the user-code in Python doesn't directly call 'stack_calc'.
This means that there is no real need for the C function to be
parallel
It could take a single pointer to any arbitrary C data structure that
can represent your sample expression. Or maybe two pointers to
arrays. Or ...
... and be just as type-unsafe as the variadic option.
No, it wouldn't.
Go on, then. Show us a typesafe alternative to printf, using your idea.
On 21/01/2024 23:51, Lawrence D'Oliveiro wrote:
On Sun, 21 Jan 2024 21:43:13 +0000, bart wrote:
On 21/01/2024 21:29, Lawrence D'Oliveiro wrote:variadic.
On Sun, 21 Jan 2024 13:27:30 +0000, bart wrote:
That is, the user-code in Python doesn't directly call 'stack_calc'. >>>>> This means that there is no real need for the C function to be
parallel
It could take a single pointer to any arbitrary C data structure
that can represent your sample expression. Or maybe two pointers to
arrays. Or ...
... and be just as type-unsafe as the variadic option.
No, it wouldn't.
Go on, then. Show us a typesafe alternative to printf, using your idea.
I said your example didn't need the C function to be variadic.
On 21/01/2024 16:24, David Brown wrote:
On 21/01/2024 03:44, Malcolm McLean wrote:
A small improvement.Variardic functions are implemented with macros and it's a bit hard
to work out what is going on. But it's not that hard. I don't think
it's a good reason for avoiding them. On the other hand, I
implemented a C++ variable length template expansion to produce a
"simple JSON" which is in effect a varidaic function with type
information. But whilst I implemented it myself, I can't remember
exactly how it is supposed to work or what the syntax means.
Variadic templates in C++ are typesafe, which is a big improvement
over C.
If you have type safety, it can be easier to know how to call the
function, because the system can help you by suggesting variables of the right type and rejecting variables of the wrong type. And because the
type is often documentation about what the parameter means.
Then of course you can always create a bug by passing a varibale of the
wrong type.
But it's not a big improvement because, if you call a function at all,
you have to know what parameters it takes and what they mean anyway.
And
whilst it does eliminate a bug, it's unlikely to be a dangerous bug, it
will usually be manifested very early and likely caught.
So not the type
of thing that is likely to much effect on delivery time or quality of
the final product.
However of course that won't always be the case,
especially if a long integer with all high bits zero happens to have the
same observable effect as the correct short integer or similar.
So there's a small advantage, but not a gamechanger.
My simpleJSON is variadic C++. But of course if you pass
"Nemployees",10.5, it will just create a JSON structure with a real
field value 10.5.
On 22/01/2024 07:58, David Brown wrote:
On 21/01/2024 22:54, Malcolm McLean wrote:No, it's because there is a benefit, and it is easy to write a computer program which checks for type. So there is a point in doing it. Then
That is contrary to the experience of most high quality software
developers. There is a reason why few modern languages are weakly
typed. Strong typing does not stop all problems, nor is it necessary
for writing correct software, and using typing for safety can involve
writing more verbose code than otherwise necessary. But it is a major
tool towards writing good code, and having checks on the code quality.
there's often a perception that because something can be done by the computer, it is important and beneficial, because the people who write
the development system must know what they are doing, and if the
computer says so, it must be correct.
Computer projects fail because the complexity of the interactions
between the sub systems exceeds the capacity of the developers to
understand them. Overwhelmingly. Not because developers sometimes pass variables of the wrong type to functions.
Computer projects fail because the complexity of the interactions
between the sub systems exceeds the capacity of the developers to
understand them. Overwhelmingly. Not because developers sometimes pass variables of the wrong type to functions.
Who has actually used a variadic function for any purpose other than implementing printf-style format strings?
On Sat, 20 Jan 2024 11:19:57 +0000 Malcolm McLean <malcolm.arthur.mclean@gmail.com> wrote:
But no-one has yet come up with an occasion where they implemented a
variadic function by choice, for code which they controlled, except for
printf style formatting. Either a hobby project or work code for which
they had ownership.
I asked a similar question on this group many years ago. One example
given was a function for concatenating strings which would accept as arguments a variable number of strings.
On 22/01/2024 19:44, Kaz Kylheku wrote:
On 2024-01-22, Malcolm McLean <malcolm.arthur.mclean@gmail.com> wrote:You can use variadic functions in C.
Computer projects fail because the complexity of the interactions
between the sub systems exceeds the capacity of the developers to
understand them. Overwhelmingly. Not because developers sometimes pass
variables of the wrong type to functions.
If passing wrong types to functions was not caught, either at compile
time, or at run time (as in dynamic languages) but simply resulted
in an object of one type being misused as another, then that would be
a huge source of bugs.
You can't tell whether wrong types are a source of bugs without working
in a typeless language.
When you use your "cat" function, for example, do you find it a problem
that is you pass a variable that isn't a character pointer, the system
will reinterpret the bits as though they were a character pointer?
I've only ever done chained strcat calls, e.g. strcat(strcat(strcat(something, "blah"), "whatever"), "nonsense").
On 22/01/2024 12:58, David Brown wrote:
On 22/01/2024 13:46, Malcolm McLean wrote:Have you tried to write a compiler or intepreter?
On 22/01/2024 07:58, David Brown wrote:
On 21/01/2024 22:54, Malcolm McLean wrote:No, it's because there is a benefit, and it is easy to write a
That is contrary to the experience of most high quality software
developers. There is a reason why few modern languages are weakly
typed. Strong typing does not stop all problems, nor is it
necessary for writing correct software, and using typing for safety
can involve writing more verbose code than otherwise necessary. But
it is a major tool towards writing good code, and having checks on
the code quality.
computer program which checks for type. So there is a point in doing
it. Then there's often a perception that because something can be
done by the computer, it is important and beneficial, because the
people who write the development system must know what they are
doing, and if the computer says so, it must be correct.
Computer projects fail because the complexity of the interactions
between the sub systems exceeds the capacity of the developers to
understand them. Overwhelmingly. Not because developers sometimes
pass variables of the wrong type to functions.
Software projects fail for countless different reasons. For many of
the possible reasons, computers can't help much. In cases where
computers (compilers, static analysis, run-time checkers, etc.) /can/
help, it makes sense to use those features - it's more efficient, and
usually more accurate.
Strong typing is one of those cases - along with many other
higher-level language features.
(And no, it's not easy to make a language and tools that provide good
checking, a comfortable and productive language, and quality tools
with efficient compilation. It is, I believe, a good deal easier to
make languages and tools with very little type checking capabilities.)
On 23/01/2024 08:07, David Brown wrote:
On 22/01/2024 23:25, Malcolm McLean wrote:Bascially it's just a grammar rule, and you'll already have a flexible grammar system because you need it for the rest of the compiler.
On 22/01/2024 12:58, David Brown wrote:
On 22/01/2024 13:46, Malcolm McLean wrote:Have you tried to write a compiler or intepreter?
On 22/01/2024 07:58, David Brown wrote:
On 21/01/2024 22:54, Malcolm McLean wrote:No, it's because there is a benefit, and it is easy to write a
That is contrary to the experience of most high quality software
developers. There is a reason why few modern languages are weakly >>>>>> typed. Strong typing does not stop all problems, nor is it
necessary for writing correct software, and using typing for
safety can involve writing more verbose code than otherwise
necessary. But it is a major tool towards writing good code, and
having checks on the code quality.
computer program which checks for type. So there is a point in
doing it. Then there's often a perception that because something
can be done by the computer, it is important and beneficial,
because the people who write the development system must know what
they are doing, and if the computer says so, it must be correct.
Computer projects fail because the complexity of the interactions
between the sub systems exceeds the capacity of the developers to
understand them. Overwhelmingly. Not because developers sometimes
pass variables of the wrong type to functions.
Software projects fail for countless different reasons. For many of
the possible reasons, computers can't help much. In cases where
computers (compilers, static analysis, run-time checkers, etc.)
/can/ help, it makes sense to use those features - it's more
efficient, and usually more accurate.
Strong typing is one of those cases - along with many other
higher-level language features.
(And no, it's not easy to make a language and tools that provide
good checking, a comfortable and productive language, and quality
tools with efficient compilation. It is, I believe, a good deal
easier to make languages and tools with very little type checking
capabilities.)
No (except for tiny DSL's).
But I also have not tried to fly a plane, yet I know that some types
of plane are easier to fly than others.
Technically it will be a "constraint" on the grammar as most grammars
can't express "function_call = function_name open_parentheses variable_of_a_type_that_matches close_parentheses".
On 22/01/2024 23:36, Lawrence D'Oliveiro wrote:
On Mon, 22 Jan 2024 23:25:22 -0000 (UTC), Blue-Maned_Hawk wrote:
I've only ever done chained strcat calls, e.g.
strcat(strcat(strcat(something, "blah"), "whatever"), "nonsense").
You’ve got to be kidding.
That was why strcat retutns a pointer. It was how it was meant to be
used. But it never caught on.
On 22/01/2024 23:36, Lawrence D'Oliveiro wrote:
On Mon, 22 Jan 2024 23:25:22 -0000 (UTC), Blue-Maned_Hawk wrote:
I've only ever done chained strcat calls, e.g.
strcat(strcat(strcat(something, "blah"), "whatever"), "nonsense").
You’ve got to be kidding.
That was why strcat retutns a pointer. It was how it was meant to be
used. But it never caught on.
Huge security hole.
On Mon, 22 Jan 2024 23:25:22 -0000 (UTC), Blue-Maned_Hawk wrote:
I've only ever done chained strcat calls, e.g.
strcat(strcat(strcat(something, "blah"), "whatever"), "nonsense").
You’ve got to be kidding.
But it is not a desirable feature for general use as it is not
type-safe.
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
On 22/01/2024 23:36, Lawrence D'Oliveiro wrote:For rather good reason. Too easy to overrun the size of the buffer.
On Mon, 22 Jan 2024 23:25:22 -0000 (UTC), Blue-Maned_Hawk wrote:That was why strcat retutns a pointer. It was how it was meant to be
I've only ever done chained strcat calls, e.g.
strcat(strcat(strcat(something, "blah"), "whatever"), "nonsense").
You’ve got to be kidding.
used. But it never caught on.
Huge security hole.
strncat
On Tue, 23 Jan 2024 15:27:25 GMT, Scott Lurndal wrote:
Huge security hole.
That was the point I was trying to make, but it seemed to go over somebody’s head ...
On Tue, 23 Jan 2024 22:28:03 -0000 (UTC), Blue-Maned_Hawk wrote:
strncat
If you can figure out how to use it properly.
[...] That is, concatenating strings with nested strcat calls scales
as O(n²), while alternatives such as "sprintf" or nested "stpcpy" (POSIX
but not standard C) scales O(n).
But you might not have known that gcc will convert a set of nested
"strcat" calls into a call to "strlen" followed by calls to "stpcpy".
On 24.01.2024 09:40, David Brown wrote:
[...] That is, concatenating strings with nested strcat calls scales
as O(n²), while alternatives such as "sprintf" or nested "stpcpy" (POSIX
but not standard C) scales O(n).
First I mistook "stpcpy" for a typo, but hey, it's there. - Nice, and
good to know it's there. Thanks.
But you might not have known that gcc will convert a set of nested
"strcat" calls into a call to "strlen" followed by calls to "stpcpy".
Interesting.
On 24/01/2024 00:31, Lawrence D'Oliveiro wrote:
On Tue, 23 Jan 2024 22:28:03 -0000 (UTC), Blue-Maned_Hawk wrote:
strncat
If you can figure out how to use it properly.
strncat is nasty, as "n" is the maximum number of characters to copy,
not the size of the destination buffer. strncpy is nasty as it wastes
effort needlessly writing null characters once the string is copied, and
does not guarantee a terminating null.
On 2024-01-24, David Brown <david.brown@hesbynett.no> wrote:
On 24/01/2024 00:31, Lawrence D'Oliveiro wrote:
On Tue, 23 Jan 2024 22:28:03 -0000 (UTC), Blue-Maned_Hawk wrote:
strncat
If you can figure out how to use it properly.
strncat is nasty, as "n" is the maximum number of characters to copy,
not the size of the destination buffer. strncpy is nasty as it wastes
effort needlessly writing null characters once the string is copied, and
does not guarantee a terminating null.
I always assumed strncpy was intended for the following kind of
situation: placing a string into a non-null-terminated array intended
for data communication or storage.
struct rec {
char first_name[15]; // null padded, not terminated
char last_name[15]; // likewise
// ...
};
Internally, you work with these as null terminated strings,
copying them out to [16] buffers.
These get written to disk, so the data has to be cleanly
padded with nulls, even if a single null is enough to
terminate short fields. You don't want random garbage
from memory written out; it could be a security problem.
strncpy helps to prepare the fields:
char fn[16]; // null terminated
/* ... */
strncpy(rec->first_name, fn, 15); // correct in all cases
The common standard C str* functions are, IMHO, extraordinarily poorly specified, and could easily have been very much easier to use correctly
and efficiently.
Chained strcat ...
I always assumed strncpy was intended for the following kind of
situation: placing a string into a non-null-terminated array intended
for data communication or storage.
struct rec {
char first_name[15]; // null padded, not terminated
char last_name[15]; // likewise
// ...
};
Internally, you work with these as null terminated strings,
copying them out to [16] buffers.
These get written to disk, so the data has to be cleanly
padded with nulls, even if a single null is enough to
terminate short fields. You don't want random garbage
from memory written out; it could be a security problem.
On Wed, 24 Jan 2024 09:40:34 +0100, David Brown wrote:
Chained strcat ...
Not that you chained it, but that you used it at all.
On 2024-01-24, David Brown <david.brown@hesbynett.no> wrote:
On 24/01/2024 00:31, Lawrence D'Oliveiro wrote:
On Tue, 23 Jan 2024 22:28:03 -0000 (UTC), Blue-Maned_Hawk wrote:
strncat
If you can figure out how to use it properly.
strncat is nasty, as "n" is the maximum number of characters to copy,
not the size of the destination buffer. strncpy is nasty as it wastes
effort needlessly writing null characters once the string is copied, and
does not guarantee a terminating null.
I always assumed strncpy was intended for the following kind of
situation: placing a string into a non-null-terminated array intended
for data communication or storage.
struct rec {
char first_name[15]; // null padded, not terminated
char last_name[15]; // likewise
// ...
};
Internally, you work with these as null terminated strings,
copying them out to [16] buffers.
These get written to disk, so the data has to be cleanly
padded with nulls, even if a single null is enough to
terminate short fields. You don't want random garbage
from memory written out; it could be a security problem.
strncpy helps to prepare the fields:
char fn[16]; // null terminated
/* ... */
strncpy(rec->first_name, fn, 15); // correct in all cases
as well as in the other direction
strncpy(fn, rec->first_name, 15); // could use strcpy
I'm using hard-coded constants for simplicity.
If fn was initialized to zeros, and always used correctly to
store a null-terminated string, there is nothing to do;
a null is guaranteed to always be present at fn[15].
Otherwise we need fn[15] = 0.
So I think that's the nice use case for strncpy; unfortunately, over
most of its life, it got clumsily used for other use cases.
Agreed. The name "strncpy" suggests that it's just "strcpy" with bounds checking, but it isn't. "strncat", on the other hand, pretty much *is* "strcat" with bounds checking. (And calling strncat() after setting the initial character of the target to '\0' actually does what some people
assume strncpy should do.)
I wrote about this a few years ago:
https://github.com/Keith-S-Thompson/the-flat-trantor-society/blob/master/002-strncpy.md
On Wed, 24 Jan 2024 09:52:59 +0100, David Brown wrote:
The common standard C str* functions are, IMHO, extraordinarily poorly
specified, and could easily have been very much easier to use correctly
and efficiently.
True. Which is why it is better to look a little beyond them <https://manpages.debian.org/7/string_copying.en.html>.
On 24/01/2024 08:40, David Brown wrote:
By doing that you are replacing undefined behaviour with defined incorrect behaviour. Now undefined behaviour will often be correct behaviour, in the context that the program as whole is bugged. The result "segmentation fault" is less wrong than "the answeer to the life, universe and everything is 4" (we added an extra e to "answer" and so ran out of buffer).
So when someone has used "strcat" in a Usenet post, I would assume that
real-world code would take appropriate care to be sure the arguments
point to valid strings, and the destinations have enough space. It's
not unlikely that the real code actually uses "strncat" to reduce the
risk of failures.
On 24/01/2024 08:40, David Brown wrote:
By doing that you are replacing undefined behaviour with defined incorrect behaviour. Now undefined behaviour will often be correct behaviour, in the context that the program as whole is bugged. The result "segmentation fault" is less wrong than "the answeer to the life, universe and everything is 4" (we added an extra e to "answer" and so ran out of buffer).
So when someone has used "strcat" in a Usenet post, I would assume that
real-world code would take appropriate care to be sure the arguments
point to valid strings, and the destinations have enough space. It's
not unlikely that the real code actually uses "strncat" to reduce the
risk of failures.
On 24/01/2024 08:40, David Brown wrote:
By doing that you are replacing undefined behaviour with defined incorrect behaviour. Now undefined behaviour will often be correct behaviour, in the context that the program as whole is bugged. The result "segmentation
So when someone has used "strcat" in a Usenet post, I would assume
that real-world code would take appropriate care to be sure the
arguments point to valid strings, and the destinations have enough
space. It's not unlikely that the real code actually uses "strncat"
to reduce the risk of failures.
fault"
is less wrong than "the answeer to the life, universe and everything is 4" (we added an extra e to "answer" and so ran out of buffer).
Not always and sometimes wrong results are better than no results, for example in video game. Better send 4 baddies rather than 42 than shut
down the game.
"strcat" is a perfectly good and useful library function.
On Thu, 25 Jan 2024 09:22:16 +0100, David Brown wrote:
"strcat" is a perfectly good and useful library function.
Can't think of any situation where it is worth using.
In article <uouejj$2ei7i$1@dont-email.me>, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
On Thu, 25 Jan 2024 09:22:16 +0100, David Brown wrote:
"strcat" is a perfectly good and useful library function.
Can't think of any situation where it is worth using.
Well, that's clearly your problem, not ours.
In article <uouejj$2ei7i$1@dont-email.me>,
Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
On Thu, 25 Jan 2024 09:22:16 +0100, David Brown wrote:
"strcat" is a perfectly good and useful library function.
Can't think of any situation where it is worth using.
Well, that's clearly your problem, not ours.
As the kids say, it's a "you problem".
On 24/01/2024 00:31, Lawrence D'Oliveiro wrote:
On Tue, 23 Jan 2024 22:28:03 -0000 (UTC), Blue-Maned_Hawk wrote:
strncat
If you can figure out how to use it properly.
strncat is nasty, as "n" is the maximum number of characters to copy,
not the size of the destination buffer.
On 25/01/2024 19:40, Keith Thompson wrote:
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:The proposal is to replace strcat with strncat() to improve behaviour
On 24/01/2024 08:40, David Brown wrote:
So when someone has used "strcat" in a Usenet post, I would assumeBy doing that you are replacing undefined behaviour with defined incorrect >>> behaviour.
that real-world code would take appropriate care to be sure the
arguments point to valid strings, and the destinations have enough
space. It's not unlikely that the real code actually uses "strncat"
to reduce the risk of failures.
What "incorrect behaviour" are you talking about?
David's premise is that the arguments point to valid strings and the
destinations have enough space. Given that premise, strcat() works.
char s[10];
strcat(s, "hello");
puts(s);
What incorrect behavior do you see in the above code?
Of course ensuring that the arguments are valid and the destination is
big enough is sometimes easier said than done, but that's not the point.
when the bufffer overflows. So the premise is that the program is bugged
and the overflow is unintentional, and there is no ideal behaviour.
By calling strncat you force the program to truncate the string to fit
the buffer. Which in reality might often be the best thing to do,
because many strings are intended for human reading, and a human reader
can guess what has happened and supply the missing characters. But the >results are always wrong, they are defined to be wrong.
With undefined behaviour they are undefined (by C). But the two most
likely results are either than the buffer will in fact have room and the >program will works as intended, though it won't be correct, or that the
UB will be defined by the platform as to give a message that there has
been a memory access error.
The proposal is to replace strcat with strncat() to improve behaviour
when the bufffer overflows. So the premise is that the program is bugged
and the overflow is unintentional, and there is no ideal behaviour.
By calling strncat you force the program to truncate the string to fit
the buffer. Which in reality might often be the best thing to do,
because many strings are intended for human reading, and a human reader
can guess what has happened and supply the missing characters. But the results are always wrong, they are defined to be wrong.
On 25/01/2024 19:40, Keith Thompson wrote:
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:The proposal is to replace strcat with strncat() to improve behaviour
On 24/01/2024 08:40, David Brown wrote:
So when someone has used "strcat" in a Usenet post, I would assumeBy doing that you are replacing undefined behaviour with defined
that real-world code would take appropriate care to be sure the
arguments point to valid strings, and the destinations have enough
space. It's not unlikely that the real code actually uses "strncat"
to reduce the risk of failures.
incorrect
behaviour.
What "incorrect behaviour" are you talking about?
David's premise is that the arguments point to valid strings and the
destinations have enough space. Given that premise, strcat() works.
char s[10];
strcat(s, "hello");
puts(s);
What incorrect behavior do you see in the above code?
Of course ensuring that the arguments are valid and the destination is
big enough is sometimes easier said than done, but that's not the point.
when the bufffer overflows.
So the premise is that the program is bugged
and the overflow is unintentional,
and there is no ideal behaviour.
David Brown <david.brown@hesbynett.no> writes:
[...]
I certainly do think strncpy, as it is defined, has its uses. And in
many situations it is a better choice than strcpy, even if it is less
efficient. But I think it was a wasted opportunity - I think
"strncpy" should have been defined the way I defined "string_copy"
above (though for consistency it should return its first argument -
and a matching stpncpy function could be made that returns an end
pointer).
Then a separate "strpad(char * s, size_t n)" function could be made
that takes a string pointer and ensures that everything beyond the
terminating '\0' is cleared to zero up to a total of n characters.
(If there is no zero in those n characters, the data is left
unchanged.)
To summarize, the problem with strncpy() is not its behavior, but its
name. The name suggests that it's something that it isn't, a
bound-checked version of strcpy(). It *is* useful for certain niche
cases. For example, I think early Unix filesystems stored file names in
a 14-byte field padded with zero or more null characters; that may have
been *the* primary use case for strncpy().
If I had a time machine, I might rename "strncpy()" to, say, "strpad()"
(not the same as the "strpad() you suggest above) and define a new "strncpy()" that behaves like setting the first character of the target
to '\0' and then calling strncat().
David Brown wrote:
On 24/01/2024 00:31, Lawrence D'Oliveiro wrote:
On Tue, 23 Jan 2024 22:28:03 -0000 (UTC), Blue-Maned_Hawk wrote:
strncat
If you can figure out how to use it properly.
strncat is nasty, as "n" is the maximum number of characters to copy,
not the size of the destination buffer.
sizeof outbuf - strlen(outbuf)
strcat should not be used. strncat isn't a suitable substitute.
snprintf does work quite well as a substitute for strcat.
On 26/01/2024 15:12, David Brown wrote:
On 26/01/2024 00:36, Malcolm McLean wrote:No. The program is trying to concatentate "strcat " and "strncat" into a
On 25/01/2024 19:40, Keith Thompson wrote:
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:The proposal is to replace strcat with strncat() to improve behaviour
On 24/01/2024 08:40, David Brown wrote:
So when someone has used "strcat" in a Usenet post, I would assume >>>>>> that real-world code would take appropriate care to be sure theBy doing that you are replacing undefined behaviour with defined
arguments point to valid strings, and the destinations have enough >>>>>> space. It's not unlikely that the real code actually uses "strncat" >>>>>> to reduce the risk of failures.
incorrect
behaviour.
What "incorrect behaviour" are you talking about?
David's premise is that the arguments point to valid strings and the
destinations have enough space. Given that premise, strcat() works.
char s[10];
strcat(s, "hello");
puts(s);
What incorrect behavior do you see in the above code?
Of course ensuring that the arguments are valid and the destination is >>>> big enough is sometimes easier said than done, but that's not the
point.
when the bufffer overflows.
Yes.
So the premise is that the program is bugged and the overflow is
unintentional,
Yes.
and there is no ideal behaviour.
Incorrect.
You started out okay, but then drew an unwarranted conclusion from
your premises.
Buffer overflow means the original "strcat" program had a bug if it
was expected to deal correctly with longer strings - longer strings
caused UB, and that is never correct execution.
Let's say the program is trying to concatenate two strings into a 10
character buffer. There are, roughly, three was to specify this :
1. It should give the concatenation for any two strings whose total
length does not exceed 9 characters.
2. It should give the concatenation for any two strings.
3. It should up to the first 9 characters of the hypothetical
unlimited length concatenation of any two strings.
If the specification is 1, then the "strcat" version is fine - it is
ideal behaviour. Garbage in, garbage out - programs are only required
to be used according to their specifications.
If the specification is 2, then it is impossible to write a program
with the required behaviour.
If the specification is 3, then strncat will give the ideal behaviour.
The "ideal behaviour" is dependent on the specification for the
program, and that has not been given here. Without the specification
or requirements, it makes no sense to talk about whether there is or
is not an "ideal behaviour", whether it is possible or not, or whether
any given program fulfils it.
ten byte buffer, and the specification is that the buffer shall hold
"strcat strncat".
But since that is more than ten bytes that is
impossible, the specification cannot be met and therefore the program is bugged.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 546 |
Nodes: | 16 (1 / 15) |
Uptime: | 160:37:31 |
Calls: | 10,385 |
Calls today: | 2 |
Files: | 14,056 |
Messages: | 6,416,493 |