Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #93090 > unrolled thread

How to copy a string safely and efficiently in C?

Started bywill hunt <glovepm@gmail.com>
First post2016-09-01 18:50 -0700
Last post2016-09-14 00:24 +0000
Articles 20 on this page of 76 — 21 participants

Back to article view | Back to comp.lang.c


Contents

  How to copy a string safely and efficiently in C? will hunt <glovepm@gmail.com> - 2016-09-01 18:50 -0700
    Re: How to copy a string safely and efficiently in C? John Gordon <gordon@panix.com> - 2016-09-02 01:58 +0000
      Re: How to copy a string safely and efficiently in C? will hunt <glovepm@gmail.com> - 2016-09-01 19:40 -0700
        Re: How to copy a string safely and efficiently in C? Geoff <geoff@invalid.invalid> - 2016-09-01 20:29 -0700
          Re: How to copy a string safely and efficiently in C? James Kuyper <jameskuyper@verizon.net> - 2016-09-02 12:29 -0400
        Re: How to copy a string safely and efficiently in C? asetofsymbols@gmail.com - 2016-09-12 13:09 -0700
          Re: How to copy a string safely and efficiently in C? Keith Thompson <kst-u@mib.org> - 2016-09-12 15:30 -0700
      Re: How to copy a string safely and efficiently in C? Keith Thompson <kst-u@mib.org> - 2016-09-01 23:08 -0700
      Re: How to copy a string safely and efficiently in C? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-04 23:59 -0700
    Re: How to copy a string safely and efficiently in C? Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2016-09-01 21:12 -0600
      Re: How to copy a string safely and efficiently in C? <william@wilbur.25thandClement.com> - 2016-09-01 22:12 -0700
    Re: How to copy a string safely and efficiently in C? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-01 23:58 -0700
    Re: How to copy a string safely and efficiently in C? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-02 10:42 +0100
      Re: How to copy a string safely and efficiently in C? Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-04 22:23 -0700
        Re: How to copy a string safely and efficiently in C? Keith Thompson <kst-u@mib.org> - 2016-09-04 23:20 -0700
          Re: How to copy a string safely and efficiently in C? mark.bluemel@gmail.com - 2016-09-05 01:03 -0700
            Re: How to copy a string safely and efficiently in C? Keith Thompson <kst-u@mib.org> - 2016-09-05 01:46 -0700
          Re: How to copy a string safely and efficiently in C? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-05 10:30 +0100
            Re: How to copy a string safely and efficiently in C? Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-10 11:25 -0700
          Re: How to copy a string safely and efficiently in C? Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-11 06:23 -0700
            Re: How to copy a string safely and efficiently in C? supercat@casperkitty.com - 2016-09-11 15:41 -0700
              Re: How to copy a string safely and efficiently in C? Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-11 23:40 -0700
                Re: How to copy a string safely and efficiently in C? Ian Collins <ian-news@hotmail.com> - 2016-09-12 21:04 +1200
                  Re: How to copy a string safely and efficiently in C? Melzzzzz <Melzzzzz@zzzzz.com> - 2016-09-12 09:21 +0000
                    Re: How to copy a string safely and efficiently in C? Ian Collins <ian-news@hotmail.com> - 2016-09-12 21:33 +1200
                    Re: How to copy a string safely and efficiently in C? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-12 10:41 +0100
                      Re: How to copy a string safely and efficiently in C? Melzzzzz <Melzzzzz@zzzzz.com> - 2016-09-12 10:48 +0000
                  Re: How to copy a string safely and efficiently in C? Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-12 07:04 -0700
    Re: How to copy a string safely and efficiently in C? Richard Heathfield <rjh@cpax.org.uk> - 2016-09-02 12:36 +0100
      Re: How to copy a string safely and efficiently in C? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-02 14:24 +0100
        Re: How to copy a string safely and efficiently in C? Richard Heathfield <rjh@cpax.org.uk> - 2016-09-02 14:51 +0100
        Re: How to copy a string safely and efficiently in C? Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-04 23:42 -0700
    Re: How to copy a string safely and efficiently in C? Richard Heathfield <rjh@cpax.org.uk> - 2016-09-02 18:05 +0100
      Re: How to copy a string safely and efficiently in C? Ike Naar <ike@iceland.freeshell.org> - 2016-09-02 19:48 +0000
    Re: How to copy a string safely and efficiently in C? cross@spitfire.i.gajendra.net (Dan Cross) - 2016-09-13 01:45 +0000
      Re: How to copy a string safely and efficiently in C? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-13 11:06 +0100
        Re: How to copy a string safely and efficiently in C? cross@spitfire.i.gajendra.net (Dan Cross) - 2016-09-13 14:09 +0000
          Re: How to copy a string safely and efficiently in C? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-13 15:30 +0100
            Re: How to copy a string safely and efficiently in C? cross@spitfire.i.gajendra.net (Dan Cross) - 2016-09-13 14:52 +0000
              Re: How to copy a string safely and efficiently in C? cross@spitfire.i.gajendra.net (Dan Cross) - 2016-09-13 14:54 +0000
                Re: How to copy a string safely and efficiently in C? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-13 17:18 +0100
                  Re: How to copy a string safely and efficiently in C? cross@spitfire.i.gajendra.net (Dan Cross) - 2016-09-13 18:15 +0000
                Re: How to copy a string safely and efficiently in C? Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-13 20:30 -0700
                  Re: How to copy a string safely and efficiently in C? cross@spitfire.i.gajendra.net (Dan Cross) - 2016-09-15 14:03 +0000
                    Re: How to copy a string safely and efficiently in C? Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-15 12:32 -0700
                      Re: How to copy a string safely and efficiently in C? luser droog <luser.droog@gmail.com> - 2016-09-15 12:45 -0700
                        Re: How to copy a string safely and efficiently in C? supercat@casperkitty.com - 2016-09-15 13:00 -0700
                          Re: How to copy a string safely and efficiently in C? Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2016-09-15 14:52 -0600
                            Re: How to copy a string safely and efficiently in C? Keith Thompson <kst-u@mib.org> - 2016-09-15 16:04 -0700
                              Re: How to copy a string safely and efficiently in C? Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2016-09-15 15:52 -0600
                                Re: How to copy a string safely and efficiently in C? Keith Thompson <kst-u@mib.org> - 2016-09-15 17:07 -0700
                          Re: How to copy a string safely and efficiently in C? Keith Thompson <kst-u@mib.org> - 2016-09-15 15:53 -0700
                            Re: How to copy a string safely and efficiently in C? Richard Heathfield <rjh@cpax.org.uk> - 2016-09-15 22:17 +0100
                              Re: How to copy a string safely and efficiently in C? Keith Thompson <kst-u@mib.org> - 2016-09-15 17:01 -0700
                            Re: How to copy a string safely and efficiently in C? supercat@casperkitty.com - 2016-09-15 16:36 -0700
                              Re: How to copy a string safely and efficiently in C? Keith Thompson <kst-u@mib.org> - 2016-09-15 19:19 -0700
                                Re: How to copy a string safely and efficiently in C? supercat@casperkitty.com - 2016-09-15 21:39 -0700
                        Re: How to copy a string safely and efficiently in C? Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-16 06:17 -0700
                          Re: How to copy a string safely and efficiently in C? Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-16 07:04 -0700
                            Re: How to copy a string safely and efficiently in C? supercat@casperkitty.com - 2016-09-16 09:11 -0700
                            Re: How to copy a string safely and efficiently in C? Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-22 22:24 -0700
                      Re: How to copy a string safely and efficiently in C? cross@spitfire.i.gajendra.net (Dan Cross) - 2016-09-19 15:15 +0000
      Re: How to copy a string safely and efficiently in C? Richard Damon <Richard@Damon-Family.org> - 2016-09-13 08:19 -0400
        Re: How to copy a string safely and efficiently in C? cross@spitfire.i.gajendra.net (Dan Cross) - 2016-09-13 14:07 +0000
          Re: How to copy a string safely and efficiently in C? supercat@casperkitty.com - 2016-09-13 07:57 -0700
            Re: How to copy a string safely and efficiently in C? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-13 17:33 +0100
              Re: How to copy a string safely and efficiently in C? cross@spitfire.i.gajendra.net (Dan Cross) - 2016-09-13 18:13 +0000
              Re: How to copy a string safely and efficiently in C? supercat@casperkitty.com - 2016-09-13 11:30 -0700
                Re: How to copy a string safely and efficiently in C? cross@spitfire.i.gajendra.net (Dan Cross) - 2016-09-13 20:03 +0000
                  Re: How to copy a string safely and efficiently in C? supercat@casperkitty.com - 2016-09-13 13:38 -0700
                    Re: How to copy a string safely and efficiently in C? cross@spitfire.i.gajendra.net (Dan Cross) - 2016-09-13 21:39 +0000
                Re: How to copy a string safely and efficiently in C? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-13 23:26 +0100
              Re: How to copy a string safely and efficiently in C? Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-13 16:14 -0700
      Re: How to copy a string safely and efficiently in C? BartC <bc@freeuk.com> - 2016-09-13 15:59 +0100
      Re: How to copy a string safely and efficiently in C? Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-13 16:07 -0700
        Re: How to copy a string safely and efficiently in C? cross@spitfire.i.gajendra.net (Dan Cross) - 2016-09-14 00:24 +0000

Page 2 of 4 — ← Prev page 1 [2] 3 4  Next page →


#93381

Fromsupercat@casperkitty.com
Date2016-09-11 15:41 -0700
Message-ID<00a7e7b0-6557-4ca2-8e7c-a9eb51b61fc8@googlegroups.com>
In reply to#93370
On Sunday, September 11, 2016 at 8:23:15 AM UTC-5, Tim Rentsch wrote:
> I would say that slightly differently.  The return value of
> strcpy() (and other str...() functions) is rarely used, because
> people forget that these functions return a result.  In many (or
> most?) cases that happens because people are used to thinking
> imperatively more than functionally.  These return values are
> actually useful noticeably more often than they are used.

The functions return the pointer that was passed in, and thus represents
something that the code already had.  It may in some cases allow some things
to be done in initialization expression which would otherwise require
statements, but that's about the extent of their usefulness.  Returning the
address of the trailing 0 byte would have been more helpful, but that's not
what the functions do.

[toc] | [prev] | [next] | [standalone]


#93382

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-09-11 23:40 -0700
Message-ID<kfntwdlk4e1.fsf@x-alumni2.alumni.caltech.edu>
In reply to#93381
supercat@casperkitty.com writes:

> On Sunday, September 11, 2016 at 8:23:15 AM UTC-5, Tim Rentsch wrote:
>> I would say that slightly differently.  The return value of
>> strcpy() (and other str...() functions) is rarely used, because
>> people forget that these functions return a result.  In many (or
>> most?) cases that happens because people are used to thinking
>> imperatively more than functionally.  These return values are
>> actually useful noticeably more often than they are used.
>
> The functions return the pointer that was passed in, [...]

I've heard this broken record before.  It isn't any more
interesting or convincing the eleventh time than it was
the first ten times.

[toc] | [prev] | [next] | [standalone]


#93387

FromIan Collins <ian-news@hotmail.com>
Date2016-09-12 21:04 +1200
Message-ID<e3n9crFbgeqU1@mid.individual.net>
In reply to#93382
On 09/12/16 06:40 PM, Tim Rentsch wrote:
> supercat@casperkitty.com writes:
>
>> On Sunday, September 11, 2016 at 8:23:15 AM UTC-5, Tim Rentsch wrote:
>>> I would say that slightly differently.  The return value of
>>> strcpy() (and other str...() functions) is rarely used, because
>>> people forget that these functions return a result.  In many (or
>>> most?) cases that happens because people are used to thinking
>>> imperatively more than functionally.  These return values are
>>> actually useful noticeably more often than they are used.
>>
>> The functions return the pointer that was passed in, [...]
>
> I've heard this broken record before.  It isn't any more
> interesting or convincing the eleventh time than it was
> the first ten times.

The Unix standard folks appear to think differently:

"The stpcpy() function shall return a pointer to the terminating NUL 
character copied into the s1 buffer."

http://pubs.opengroup.org/onlinepubs/9699919799/functions/strcpy.html

-- 
Ian

[toc] | [prev] | [next] | [standalone]


#93388

FromMelzzzzz <Melzzzzz@zzzzz.com>
Date2016-09-12 09:21 +0000
Message-ID<nr5s2u$1b9$8@news.albasani.net>
In reply to#93387
On 2016-09-12, Ian Collins <ian-news@hotmail.com> wrote:
> On 09/12/16 06:40 PM, Tim Rentsch wrote:
>> supercat@casperkitty.com writes:
>>
>>> On Sunday, September 11, 2016 at 8:23:15 AM UTC-5, Tim Rentsch wrote:
>>>> I would say that slightly differently.  The return value of
>>>> strcpy() (and other str...() functions) is rarely used, because
>>>> people forget that these functions return a result.  In many (or
>>>> most?) cases that happens because people are used to thinking
>>>> imperatively more than functionally.  These return values are
>>>> actually useful noticeably more often than they are used.
>>>
>>> The functions return the pointer that was passed in, [...]
>>
>> I've heard this broken record before.  It isn't any more
>> interesting or convincing the eleventh time than it was
>> the first ten times.
>
> The Unix standard folks appear to think differently:
>
> "The stpcpy() function shall return a pointer to the terminating NUL 
> character copied into the s1 buffer."
>
> http://pubs.opengroup.org/onlinepubs/9699919799/functions/strcpy.html
>
Hm, gcc returns pointer to result. What does this means? We can't rely on
what strcpy returns?

[toc] | [prev] | [next] | [standalone]


#93389

FromIan Collins <ian-news@hotmail.com>
Date2016-09-12 21:33 +1200
Message-ID<e3nb2lFbgeqU2@mid.individual.net>
In reply to#93388
On 09/12/16 09:21 PM, Melzzzzz wrote:
> On 2016-09-12, Ian Collins <ian-news@hotmail.com> wrote:
>> On 09/12/16 06:40 PM, Tim Rentsch wrote:
>>> supercat@casperkitty.com writes:
>>>
>>>> On Sunday, September 11, 2016 at 8:23:15 AM UTC-5, Tim Rentsch wrote:
>>>>> I would say that slightly differently.  The return value of
>>>>> strcpy() (and other str...() functions) is rarely used, because
>>>>> people forget that these functions return a result.  In many (or
>>>>> most?) cases that happens because people are used to thinking
>>>>> imperatively more than functionally.  These return values are
>>>>> actually useful noticeably more often than they are used.
>>>>
>>>> The functions return the pointer that was passed in, [...]
>>>
>>> I've heard this broken record before.  It isn't any more
>>> interesting or convincing the eleventh time than it was
>>> the first ten times.
>>
>> The Unix standard folks appear to think differently:
>>
>> "The stpcpy() function shall return a pointer to the terminating NUL
>> character copied into the s1 buffer."
>>
>> http://pubs.opengroup.org/onlinepubs/9699919799/functions/strcpy.html
>>
> Hm, gcc returns pointer to result. What does this means? We can't rely on
> what strcpy returns?

Do what?  The library function returns hat the standard says it returns, 
gcc return success or failure :)

-- 
Ian

[toc] | [prev] | [next] | [standalone]


#93390

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-12 10:41 +0100
Message-ID<8737l5tpyo.fsf@bsb.me.uk>
In reply to#93388
Melzzzzz <Melzzzzz@zzzzz.com> writes:

> On 2016-09-12, Ian Collins <ian-news@hotmail.com> wrote:
>> On 09/12/16 06:40 PM, Tim Rentsch wrote:
>>> supercat@casperkitty.com writes:
>>>
>>>> On Sunday, September 11, 2016 at 8:23:15 AM UTC-5, Tim Rentsch wrote:
>>>>> I would say that slightly differently.  The return value of
>>>>> strcpy() (and other str...() functions) is rarely used, because
>>>>> people forget that these functions return a result.  In many (or
>>>>> most?) cases that happens because people are used to thinking
>>>>> imperatively more than functionally.  These return values are
>>>>> actually useful noticeably more often than they are used.
>>>>
>>>> The functions return the pointer that was passed in, [...]
>>>
>>> I've heard this broken record before.  It isn't any more
>>> interesting or convincing the eleventh time than it was
>>> the first ten times.
>>
>> The Unix standard folks appear to think differently:
>>
>> "The stpcpy() function shall return a pointer to the terminating NUL 
>> character copied into the s1 buffer."
>>
>> http://pubs.opengroup.org/onlinepubs/9699919799/functions/strcpy.html
>>
> Hm, gcc returns pointer to result. What does this means? We can't rely on
> what strcpy returns?

stpcpy != strcpy

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#93391

FromMelzzzzz <Melzzzzz@zzzzz.com>
Date2016-09-12 10:48 +0000
Message-ID<nr6154$ma5$2@news.albasani.net>
In reply to#93390
On 2016-09-12, Ben Bacarisse <ben.usenet@bsb.me.uk> wrote:
> Melzzzzz <Melzzzzz@zzzzz.com> writes:
>
>> On 2016-09-12, Ian Collins <ian-news@hotmail.com> wrote:
>>>
>>> The Unix standard folks appear to think differently:
>>>
>>> "The stpcpy() function shall return a pointer to the terminating NUL 
>>> character copied into the s1 buffer."
>>>
>>> http://pubs.opengroup.org/onlinepubs/9699919799/functions/strcpy.html
>>>
>> Hm, gcc returns pointer to result. What does this means? We can't rely on
>> what strcpy returns?
>
> stpcpy != strcpy
>
Aaaaah, I missed that, sorry ;(

[toc] | [prev] | [next] | [standalone]


#93394

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-09-12 07:04 -0700
Message-ID<kfnlgyxjjsl.fsf@x-alumni2.alumni.caltech.edu>
In reply to#93387
Ian Collins <ian-news@hotmail.com> writes:

> On 09/12/16 06:40 PM, Tim Rentsch wrote:
>> supercat@casperkitty.com writes:
>>
>>> On Sunday, September 11, 2016 at 8:23:15 AM UTC-5, Tim Rentsch wrote:
>>>> I would say that slightly differently.  The return value of
>>>> strcpy() (and other str...() functions) is rarely used, because
>>>> people forget that these functions return a result.  In many (or
>>>> most?) cases that happens because people are used to thinking
>>>> imperatively more than functionally.  These return values are
>>>> actually useful noticeably more often than they are used.
>>>
>>> The functions return the pointer that was passed in, [...]
>>
>> I've heard this broken record before.  It isn't any more
>> interesting or convincing the eleventh time than it was
>> the first ten times.
>
> The Unix standard folks appear to think differently:
>
> "The stpcpy() function shall return a pointer to the terminating NUL
> character copied into the s1 buffer."
>
> http://pubs.opengroup.org/onlinepubs/9699919799/functions/strcpy.html

I think you are imagining I'm saying things other than what I
actually said.  There is no inconsistency between what I said
and the Open Group's decision to define the stpcpy() function.

[toc] | [prev] | [next] | [standalone]


#93101

FromRichard Heathfield <rjh@cpax.org.uk>
Date2016-09-02 12:36 +0100
Message-ID<nqbo71$ou7$1@dont-email.me>
In reply to#93090
On 02/09/16 02:50, will hunt wrote:
> should I use strncpy or snprintf, and why?

You have no doubt read the other answers by now. If and only if you 
aren't happy with any of them, read on.

I generally prefer to write a function that does exactly what's 
required, rather than pick one particular library function for general 
use. And you need to establish exactly what's required. In this case, 
the key point at issue is, I think, whether it's okay to discard data if 
there's too much.

If losing data is acceptable, you can do this:

#include <string.h>

/* Copy As Much Of String As Possible (camosap) */
/* target: destination string */
/* maxlen: amount of storage allocated for string, inc null */
/* source: place from which to copy data */
/* return: 1 if truncated, else 0 */

int camosap(char *target, size_t maxlen, char *source)
{
   int truncated = 0;
   size_t len = strlen(source);
   if(len >= maxlen)
   {
     /* if the strings are guaranteed not to overlap, you
        can use memcpy instead of memmove */
     memmove(target, source, len);
     target[len] = '\0';
     truncated = 1;
   }
   else
   {
     strcpy(target, source);
   }
   return truncated;
}

If losing data is unacceptable, then you can make sure there's enough by 
allocating it yourself:

#include <stdlib.h>
#include <string.h>

char *dupstring(const char *source)
{
   size_t len = strlen(source) + 1;
   char *new = malloc(len);
   if(new != NULL)
   {
     memcpy(new, source, len);
   }
   return new;
}

but then you take on responsibility for ensuring (as far too many sloppy 
programmers do not ensure) that the allocation was successful, and of 
course you have to free() it when you've finished with it.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within

[toc] | [prev] | [next] | [standalone]


#93105

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-02 14:24 +0100
Message-ID<87k2eu4ep7.fsf@bsb.me.uk>
In reply to#93101
Richard Heathfield <rjh@cpax.org.uk> writes:

> On 02/09/16 02:50, will hunt wrote:
>> should I use strncpy or snprintf, and why?
<snip>
> If losing data is acceptable, you can do this:
>
> #include <string.h>
>
> /* Copy As Much Of String As Possible (camosap) */
> /* target: destination string */
> /* maxlen: amount of storage allocated for string, inc null */
> /* source: place from which to copy data */
> /* return: 1 if truncated, else 0 */
>
> int camosap(char *target, size_t maxlen, char *source)
> {
>   int truncated = 0;
>   size_t len = strlen(source);
>   if(len >= maxlen)
>   {
>     /* if the strings are guaranteed not to overlap, you
>        can use memcpy instead of memmove */
>     memmove(target, source, len);
>     target[len] = '\0';
>     truncated = 1;
>   }
>   else
>   {
>     strcpy(target, source);
>   }
>   return truncated;
> }

Several things have gone wrong with that.  You overrun the buffer by
using len rather than maxlen and you are careful to allow copying
between overlapping objects in once case and then use strcpy in the
other (strcpy is undefined when the source and destination overlap).
And the setting of the null was probably intended to be

  target[maxlen - 1] = '\0';

I find using maxlen for a size (i.e. a string length plus the
terminating null) to be rather confusing, especially as you also have
len which is a string length (excluding the terminating null).

If I had to maintain house style, I think I'd rewrite it, with a const
added as well, like this:

  int camosap(char *target, size_t target_size, const char *source)
  {
    int truncated = 0;
    size_t len = strlen(source);
    if (len >= target_size)
    {
      /* if the strings are guaranteed not to overlap, you
         can use memcpy instead of memmove */
      memmove(target, source, target_size - 1);
      target[target_size - 1] = '\0';
      truncated = 1;
    }
    else
    {
      memmove(target, source, len + 1);
    }
    return truncated;
  }

But I'd probably actually write like this, swapping the sense of the
return value as well (I suspect you favour zero for success for Anna
Karenina reasons):

  int camosap(char *target, size_t target_size, const char *source)
  {
    size_t source_size = strlen(source) + 1;
    if (source_size > target_size) {
      memmove(target, source, target_size - 1);
      target[target_size - 1] = '\0';
      return 0;
    }
    memmove(target, source, source_size);
    return 1;
  }

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#93106

FromRichard Heathfield <rjh@cpax.org.uk>
Date2016-09-02 14:51 +0100
Message-ID<nqc04h$jld$1@dont-email.me>
In reply to#93105
On 02/09/16 14:24, Ben Bacarisse wrote:
> Richard Heathfield <rjh@cpax.org.uk> writes:
>
>> On 02/09/16 02:50, will hunt wrote:
>>> should I use strncpy or snprintf, and why?
> <snip>
>> If losing data is acceptable, you can do this:
>>
>> #include <string.h>
>>
>> /* Copy As Much Of String As Possible (camosap) */
>> /* target: destination string */
>> /* maxlen: amount of storage allocated for string, inc null */
>> /* source: place from which to copy data */
>> /* return: 1 if truncated, else 0 */
>>
>> int camosap(char *target, size_t maxlen, char *source)
>> {
>>   int truncated = 0;
>>   size_t len = strlen(source);
>>   if(len >= maxlen)
>>   {
>>     /* if the strings are guaranteed not to overlap, you
>>        can use memcpy instead of memmove */
>>     memmove(target, source, len);
>>     target[len] = '\0';
>>     truncated = 1;
>>   }
>>   else
>>   {
>>     strcpy(target, source);
>>   }
>>   return truncated;
>> }
>
> Several things have gone wrong with that.

I've got a bad feeling about this.

> You overrun the buffer by
> using len rather than maxlen

Ouch one.

> and you are careful to allow copying
> between overlapping objects in once case and then use strcpy in the
> other (strcpy is undefined when the source and destination overlap).

Ouch two.

> And the setting of the null was probably intended to be
>
>   target[maxlen - 1] = '\0';

Ouch three.

> I find using maxlen for a size (i.e. a string length plus the
> terminating null) to be rather confusing, especially as you also have
> len which is a string length (excluding the terminating null).

Ouch four. In the grand scheme of ouches (as seen above), it's more of 
an "ooh", but I do take your point. Believe it or not... and I know 
you'll find it difficult to believe... I did actually think about that 
issue. But, on balance, I think I'll spend the rest of the day doing 
documentation. Today is clearly not meant to be a programming day.

>
> If I had to maintain house style, I think I'd rewrite it, with a const
> added as well, like this:

Ouch five. And, when I saw that you'd replied but hadn't yet got to your 
reply, I reviewed my code, and the missing const was the /only/ thing I 
could see that was wrong with the code! Today is so not being a good 
day. But, of course, that's why we have code reviews.

There was an ouch six, too - the name. It's terrible. And I knew it was 
terrible when I wrote it. I just wanted a name that wasn't mystrcpy.

>
>   int camosap(char *target, size_t target_size, const char *source)
>   {
>     int truncated = 0;
>     size_t len = strlen(source);
>     if (len >= target_size)
>     {
>       /* if the strings are guaranteed not to overlap, you
>          can use memcpy instead of memmove */
>       memmove(target, source, target_size - 1);
>       target[target_size - 1] = '\0';
>       truncated = 1;
>     }
>     else
>     {
>       memmove(target, source, len + 1);
>     }
>     return truncated;
>   }
>
> But I'd probably actually write like this, swapping the sense of the
> return value as well (I suspect you favour zero for success for Anna
> Karenina reasons):

Right. If it worked, it worked. If it didn't work, I want to know why.

For functions that return pointers, the indication of failure that makes 
most sense to me is NULL, and I think the C standard library bears me 
out on this (fopen, malloc, strchr, etc). (Alas, this technique can't 
tell me why it failed.)

For integer returns, however, 0 makes an awful lot of sense. -1 would 
/also/ make a lot of sense, with the return value otherwise being an 
index into an array of reasons for screwup, but (a) that doesn't sit 
well with the standard library (fclose, rename, etc), and (b) it sounds 
terribly messy.

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within

[toc] | [prev] | [next] | [standalone]


#93208

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-09-04 23:42 -0700
Message-ID<kfneg4yn8zl.fsf@x-alumni2.alumni.caltech.edu>
In reply to#93105
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

> Richard Heathfield <rjh@cpax.org.uk> writes:
>
>> On 02/09/16 02:50, will hunt wrote:
>>> should I use strncpy or snprintf, and why?
>
> <snip>
>
>> If losing data is acceptable, you can do this:
>>
>> #include <string.h>
>>
>> /* Copy As Much Of String As Possible (camosap) */
>> /* target:  destination string */
>> /* maxlen:  amount of storage allocated for string, inc null */
>> /* source:  place from which to copy data */
>> /* return:  1 if truncated, else 0 */
>>
>> int camosap(char *target, size_t maxlen, char *source)
>> {
>>   int truncated = 0;
>>   size_t len = strlen(source);
>>   if(len >= maxlen)
>>   {
>>     /* if the strings are guaranteed not to overlap, you
>>        can use memcpy instead of memmove */
>>     memmove(target, source, len);
>>     target[len] = '\0';
>>     truncated = 1;
>>   }
>>   else
>>   {
>>     strcpy(target, source);
>>   }
>>   return truncated;
>> }
>
> Several things have gone wrong with that.  You overrun the buffer by
> using len rather than maxlen and you are careful to allow copying
> between overlapping objects in once case and then use strcpy in the
> other (strcpy is undefined when the source and destination overlap).
> And the setting of the null was probably intended to be
>
>   target[maxlen - 1] = '\0';
>
> I find using maxlen for a size (i.e. a string length plus the
> terminating null) to be rather confusing, especially as you also have
> len which is a string length (excluding the terminating null).
>
> If I had to maintain house style, I think I'd rewrite it, with a const
> added as well, like this:
>
>   int camosap(char *target, size_t target_size, const char *source)
>   {
>     int truncated = 0;
>     size_t len = strlen(source);
>     if (len >= target_size)
>     {
>       /* if the strings are guaranteed not to overlap, you
>          can use memcpy instead of memmove */
>       memmove(target, source, target_size - 1);
>       target[target_size - 1] = '\0';
>       truncated = 1;
>     }
>     else
>     {
>       memmove(target, source, len + 1);
>     }
>     return truncated;
>   }
>
> But I'd probably actually write like this, swapping the sense of the
> return value as well (I suspect you favour zero for success for Anna
> Karenina reasons):
>
>   int camosap(char *target, size_t target_size, const char *source)
>   {
>     size_t source_size = strlen(source) + 1;
>     if (source_size > target_size) {
>       memmove(target, source, target_size - 1);
>       target[target_size - 1] = '\0';
>       return 0;
>     }
>     memmove(target, source, source_size);
>     return 1;
>   }

Two more alternatives: one that uses library functions, and one
that doesn't.  The second one has different semantics in some
cases where the operands overlap, but still avoids undefined
behavior.  The set of return values is expanded to deal with the
case that the "size" is zero.  (Disclaimer:  not tested.)

    int
    camosap( char *d, size_t n, const char *s ){
        const char *t  = memchr( s, 0, n );
        size_t const k = t ? t-s+1 : n;
        memmove( d, s, k );
        return  t ?  0   :   n > 0 ?  d[n-1] = 0,  1   :    -1;
    }


    int
    camosap( char *d, size_t n, const char *s ){
        return  n > 1  &&  (*d = *s)  ?  camosap( d+1, n-1, s+1 )
            :   n > 0  &&  *s == 0    ?  *d = 0,  0
            :   n > 0                 ?  *d = 0,  1
            :                            -1;
    }

[toc] | [prev] | [next] | [standalone]


#93125

FromRichard Heathfield <rjh@cpax.org.uk>
Date2016-09-02 18:05 +0100
Message-ID<nqcbhb$thn$1@dont-email.me>
In reply to#93090
On 02/09/16 17:22, Stefan Ram wrote:
> will hunt <glovepm@gmail.com> writes:
>> should I use strncpy or snprintf, and why?
>
>   It is a good tradition in the Usenet to write
>   the full question into the body of the post.
>
>   If safety is an issue, one can check out
>
> K.3.7.1.4 The strncpy_s function

(a) Optional - compilers need not provide it.
(b) This doesn't address the issue of incomplete copies.
(c) It is easy (as I have already demonstrated in this thread) to 
specify the wrong length.

>
>   and
>
> K.3.5.3.5 The snprintf_s function

The same arguments apply.

There is quite simply no substitute for taking care to ensure that the 
destination is sufficiently large to receive all the required data from 
the source. (Again, I have proved this, in the most embarrassing way 
possible, earlier in this thread.)

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within

[toc] | [prev] | [next] | [standalone]


#93131

FromIke Naar <ike@iceland.freeshell.org>
Date2016-09-02 19:48 +0000
Message-ID<slrn3vfsnsjlrl.s0n.ike@iceland.freeshell.org>
In reply to#93125
On 2016-09-02, Stefan Ram <ram@zedat.fu-berlin.de> wrote:
>   The implementation of ?salsub? below /is/ using ?strncpy?,
>   but I hope that this usage is correct.

Or use memcpy which has simpler semantics and does the job just as well.

>   [...]
>
>   s_type.c
>
> #include <stdarg.h> /* va_list, va_start, va_end   */
> #include <stdio.h>  /* vsnprintf, size_t, vsprintf */
> #include <string.h> /* strncpy                     */
> #include <stdlib.h> /* malloc, free                */
> #include <stddef.h> /* ptrdiff_t                   */
> #include "s_type.h" /* s_type                      */

In my opinion it is best to move the #include of a header file
(in this case, s_type.h) to the very top of its implementation
(in this case, s_type.c).
Reason: this way one can easily check whether the header
s_type.h is self-contained and does not depend on other includes
used by its implementation s_type.c .

> [...]
> /* not tested! */
> s_type salfmt( s_type const f, ... )
> { va_list a; 
>   va_start(a,f);
>   salfmtv( f, a );

That should be:

    s_type const b = salfmtv(f, a);

>   va_end(a);
>   return b; }

[toc] | [prev] | [next] | [standalone]


#93408

Fromcross@spitfire.i.gajendra.net (Dan Cross)
Date2016-09-13 01:45 +0000
Message-ID<nr7lnl$71m$1@reader2.panix.com>
In reply to#93090
In article <0b30b0cc-f7c5-4928-8acb-56bf2364797b@googlegroups.com>,
will hunt  <glovepm@gmail.com> wrote:
>should I use strncpy or snprintf, and why?

This has been covered, but I'll throw my hat in the ring for the,
"neither" camp.

The biggest deficiencies of strncpy() have to do with its surprising
semantics: it was originally written for copying data into
fixed-width fields of data structures that were written to disk
(actually as part of a filesystem).  Thus, it zeros out the part of
the destination after the end of the source if the source is shorter
than the buffer size (instead of just appending a single NUL
terminator), and possibly won't NUL terminate if the source is of
length equal-to or longer than the size argument.  It always writes
exactly 'size' characters, which is inefficient for short source
strings and large destination buffers.

The possible lack of NUL termination requires care on the part of the
programmer and is sufficiently non-intuitive that it is often
overlooked: this has been a fruitful source of errors over the years.
Further, there's no way to detect truncation (short of comparison
against the source string after the copy or similar).

snprintf() doesn't have the NUL-termination or zeroing problem, but
requires a lot of machinery (all the rest of printf, which is
complicated in its full glory) and is inefficient.  However,
snprintf() *does* return a useful value that can be used to probe
for truncation.

The,

        *dst = 0;
        strncat(dst, src, size - 1);

trick is clever and reasonably efficient, but leaves the programmer
no way to detect truncation (again, unless followed by a comparison
against the source or something).

It should be noted that this "compare against the source" business as
a workaround to detect truncation is redundant: the copying routine
could report if it truncates or not, so requiring a second probing
step should not be necessary.  Perhaps that's fine for one's
particular application, but the general problem persists.

To summarize, no string-copying function in the C standard library
provides an acceptable combination of efficiency, safety and the
ability to detect truncation.

The OpenBSD people recognized this some years ago and came up with
functions that had the right properties: strlcpy() and strlcat().
These are pretty simple. They will *always* terminate a greater-than-
zero length destination buffer, they will never write more than one
terminating NUL character, and they return a value that can be used
to detect truncation. They are available from the OpenBSD
distribution under a permissive license and have made it into most
of the BSD distributions, the Mac, and (I think) Solaris.  Most Linux
distributions provide copies in a BSD compatibility library, though
they were rejected from glibc because, well, Ulrich Drepper didn't
like them.

An ersatz implementation of strlcpy() taken from
http://pub.gajendra.net/src/strlcpy.c is:

#include <stddef.h>
#include <string.h>

size_t
strlcpy(char *dst, const char *src, size_t size)
{
       	size_t len, srclen;

       	/*
       	 * Get the length of the source first, test for the
       	 * pathological case, then copy as much as we can.
       	 */
       	srclen = strlen(src);
       	if (size-- == 0)
       		return(srclen);
       	len = (size < srclen) ? size : srclen;
       	memmove(dst, src, len);
       	dst[len] = '\0';

       	return(srclen);
}

Similarly, an implementation of strlcat() taken from
http://pub.gajendra.net/src/strlcat.c is:

#include <stddef.h>
#include <string.h>

size_t
strlcat(char *dst, const char *src, size_t size)
{
	char *p;
	size_t len;

	/*
	 * This mimics the OpenBSD semantics most closely.
	 *
	 * We would like to use strlen() here, but the idea is to
	 * catch cases where dst isn't a C-style string, and this
	 * function is (presumably) called in error.
	 */
	p = memchr(dst, '\0', size);
	if (p == NULL)
		p = dst + size;
	len = p - dst;

	return(len + strlcpy(p, src, size - len));
}

Feel free to use these, if you'd like (I'm the original author of
these versions and have put them into the public domain).

	- Dan C.

[toc] | [prev] | [next] | [standalone]


#93410

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-13 11:06 +0100
Message-ID<87h99kqfjx.fsf@bsb.me.uk>
In reply to#93408
cross@spitfire.i.gajendra.net (Dan Cross) writes:

> In article <0b30b0cc-f7c5-4928-8acb-56bf2364797b@googlegroups.com>,
> will hunt  <glovepm@gmail.com> wrote:
>>should I use strncpy or snprintf, and why?
<snip lots of stuff>

> The,
>
>         *dst = 0;
>         strncat(dst, src, size - 1);
>
> trick is clever and reasonably efficient, but leaves the programmer
> no way to detect truncation (again, unless followed by a comparison
> against the source or something).

As written, yes, but a test similar to the one I use for detecting long
lines with fgets can give you this information in O(1) time (i.e. with
no re-scan for length or comparison).  You just add one more null byte:

  dst[0] = dst[size - 2] = 0;
  strncat(dst, src, size - 1);

after which the expression dst[size - 2] && src[size - 1] is true if,
and only if, there was truncation.

(Note: the context was with a constant STR_SIZE where you could be
permitted to know that STR_SIZE - 2 was valid.  Real life may not be so
simple.)

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#93415

Fromcross@spitfire.i.gajendra.net (Dan Cross)
Date2016-09-13 14:09 +0000
Message-ID<nr91b6$mpd$2@reader2.panix.com>
In reply to#93410
In article <87h99kqfjx.fsf@bsb.me.uk>,
Ben Bacarisse  <ben.usenet@bsb.me.uk> wrote:
>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>
>> In article <0b30b0cc-f7c5-4928-8acb-56bf2364797b@googlegroups.com>,
>> will hunt  <glovepm@gmail.com> wrote:
>>>should I use strncpy or snprintf, and why?
><snip lots of stuff>
>
>> The,
>>
>>         *dst = 0;
>>         strncat(dst, src, size - 1);
>>
>> trick is clever and reasonably efficient, but leaves the programmer
>> no way to detect truncation (again, unless followed by a comparison
>> against the source or something).
>
>As written, yes, but a test similar to the one I use for detecting long
>lines with fgets can give you this information in O(1) time (i.e. with
>no re-scan for length or comparison).  You just add one more null byte:
>
>  dst[0] = dst[size - 2] = 0;
>  strncat(dst, src, size - 1);
>
>after which the expression dst[size - 2] && src[size - 1] is true if,
>and only if, there was truncation.
>
>(Note: the context was with a constant STR_SIZE where you could be
>permitted to know that STR_SIZE - 2 was valid.  Real life may not be so
>simple.)

That's clever, but sadly as you note it won't work in all cases
specifically, when STR_SIZE - 2 is invalid. That case may seem
superfluous, but one never knows.

	- Dan C.

[toc] | [prev] | [next] | [standalone]


#93417

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-13 15:30 +0100
Message-ID<87wpifq3db.fsf@bsb.me.uk>
In reply to#93415
cross@spitfire.i.gajendra.net (Dan Cross) writes:

> In article <87h99kqfjx.fsf@bsb.me.uk>,
> Ben Bacarisse  <ben.usenet@bsb.me.uk> wrote:
>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>
>>> In article <0b30b0cc-f7c5-4928-8acb-56bf2364797b@googlegroups.com>,
>>> will hunt  <glovepm@gmail.com> wrote:
>>>>should I use strncpy or snprintf, and why?
>><snip lots of stuff>
>>
>>> The,
>>>
>>>         *dst = 0;
>>>         strncat(dst, src, size - 1);
>>>
>>> trick is clever and reasonably efficient, but leaves the programmer
>>> no way to detect truncation (again, unless followed by a comparison
>>> against the source or something).
>>
>>As written, yes, but a test similar to the one I use for detecting long
>>lines with fgets can give you this information in O(1) time (i.e. with
>>no re-scan for length or comparison).  You just add one more null byte:
>>
>>  dst[0] = dst[size - 2] = 0;
>>  strncat(dst, src, size - 1);
>>
>>after which the expression dst[size - 2] && src[size - 1] is true if,
>>and only if, there was truncation.
>>
>>(Note: the context was with a constant STR_SIZE where you could be
>>permitted to know that STR_SIZE - 2 was valid.  Real life may not be so
>>simple.)
>
> That's clever, but sadly as you note it won't work in all cases
> specifically, when STR_SIZE - 2 is invalid. That case may seem
> superfluous, but one never knows.

The original assumed that size was at least 1.  If that's reasonable you
can test

  src[size - 1] && size > 1 && dst[size - 2]

and if size could be 0 the test gets more complicated still but not very
much more complicated.  The most obvious one being

  size && src[size - 1] && size > 1 && dst[size - 2]

It may not be of any practical value, but I think it's interesting to
know that O(1) overflow detection is always possible in these cases.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#93419

Fromcross@spitfire.i.gajendra.net (Dan Cross)
Date2016-09-13 14:52 +0000
Message-ID<nr93rt$lgt$1@reader2.panix.com>
In reply to#93417
In article <87wpifq3db.fsf@bsb.me.uk>,
Ben Bacarisse  <ben.usenet@bsb.me.uk> wrote:
>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>> In article <87h99kqfjx.fsf@bsb.me.uk>,
>> Ben Bacarisse  <ben.usenet@bsb.me.uk> wrote:
>>>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>>>
>>>> In article <0b30b0cc-f7c5-4928-8acb-56bf2364797b@googlegroups.com>,
>>>> will hunt  <glovepm@gmail.com> wrote:
>>>>>should I use strncpy or snprintf, and why?
>>><snip lots of stuff>
>>>
>>>> The,
>>>>
>>>>         *dst = 0;
>>>>         strncat(dst, src, size - 1);
>>>>
>>>> trick is clever and reasonably efficient, but leaves the programmer
>>>> no way to detect truncation (again, unless followed by a comparison
>>>> against the source or something).
>>>
>>>As written, yes, but a test similar to the one I use for detecting long
>>>lines with fgets can give you this information in O(1) time (i.e. with
>>>no re-scan for length or comparison).  You just add one more null byte:
>>>
>>>  dst[0] = dst[size - 2] = 0;
>>>  strncat(dst, src, size - 1);
>>>
>>>after which the expression dst[size - 2] && src[size - 1] is true if,
>>>and only if, there was truncation.
>>>
>>>(Note: the context was with a constant STR_SIZE where you could be
>>>permitted to know that STR_SIZE - 2 was valid.  Real life may not be so
>>>simple.)
>>
>> That's clever, but sadly as you note it won't work in all cases
>> specifically, when STR_SIZE - 2 is invalid. That case may seem
>> superfluous, but one never knows.
>
>The original assumed that size was at least 1.  If that's reasonable you
>can test
>
>  src[size - 1] && size > 1 && dst[size - 2]
>
>and if size could be 0 the test gets more complicated still but not very
>much more complicated.  The most obvious one being
>
>  size && src[size - 1] && size > 1 && dst[size - 2]
>
>It may not be of any practical value, but I think it's interesting to
>know that O(1) overflow detection is always possible in these cases.

Yes yes, that's true, but surely we can see that one approaches a point
of diminishing returns with these sorts of shenanigans. One could simply
use strlcpy() and avoid all of this, no?

	- Dan C.

[toc] | [prev] | [next] | [standalone]


#93420

Fromcross@spitfire.i.gajendra.net (Dan Cross)
Date2016-09-13 14:54 +0000
Message-ID<nr93vt$lgt$2@reader2.panix.com>
In reply to#93419
In article <nr93rt$lgt$1@reader2.panix.com>,
Dan Cross <cross@spitfire.i.gajendra.net> wrote:
>In article <87wpifq3db.fsf@bsb.me.uk>,
>Ben Bacarisse  <ben.usenet@bsb.me.uk> wrote:
>>> [snip]
>>
>>The original assumed that size was at least 1.  If that's reasonable you
>>can test
>>
>>  src[size - 1] && size > 1 && dst[size - 2]
>>
>>and if size could be 0 the test gets more complicated still but not very
>>much more complicated.  The most obvious one being
>>
>>  size && src[size - 1] && size > 1 && dst[size - 2]
>>
>>It may not be of any practical value, but I think it's interesting to
>>know that O(1) overflow detection is always possible in these cases.
>
>Yes yes, that's true, but surely we can see that one approaches a point
>of diminishing returns with these sorts of shenanigans. One could simply
>use strlcpy() and avoid all of this, no?

And to wit: Surely one would not expect a reasonable program to duplicate
these checks at every strncat() call site. Instead, one would wrap this
sequence of code up into some kind of function; at that point, one may as
well simply call the 8 line strlcpy().

	- Dan C.

[toc] | [prev] | [next] | [standalone]


Page 2 of 4 — ← Prev page 1 [2] 3 4  Next page →

Back to top | Article view | comp.lang.c


csiph-web