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 16 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 4 of 4 — ← Prev page 1 2 3 [4]


#93924

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-09-22 22:24 -0700
Message-ID<kfnr38bdw7q.fsf@x-alumni2.alumni.caltech.edu>
In reply to#93619
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:

> On Friday, September 16, 2016 at 2:17:27 PM UTC+1, Tim Rentsch wrote:
>>
>>>> The problem with strncpy() is not what functionality it provides
>>>> but the name used to provide it.  In retrospect I think it should
>>>> have been called something like strnotwhatyouexpectcpy().
>>>
>>> I suggest char_array_cpy() or fixed_field_cpy().  Maybe *fld*.
>>
>> All of these (mine included) are stylistically at odds with other
>> standard library functions.  In light of that I withdraw my
>> previous strawman and offer strnwtf() as a possible replacement
>> (the last part being short for "write truncated field").
>>
>> (I really hope no one is taking these suggestions seriously.)
>
> Standardisation actually narrows the functionality available to the programmer,
> until the standard sweeps the board and every non-conforming platform
> becomes obsolete.  That can take a long time.
> You can't use the standard identifier because it will be available on some
> systems and not on others.  You can try conditional define guards, but you just
> dig a hole for yourself going too far down that route - the conditionals keep
> on breaking.
> Now with isnan() we're really in trouble.  We can't use the identifier isnan()
> because it is in the process of standardisation, and we can't write it portably
> as #define myisnan(x) ( (x)==(x) ? 0 : 1) because some compiler will optimise
> out the "redundant" test.

I find these statements silly or nonsensical on a variety of
levels.  For starters, isnan() is not currently in the process of
standardization:  in point of fact, that particular process
finished more than fifteen years ago.  The idea that a standard
(either original or a revised version) is not usable until every
single implementation is conforming is laughable.  As for using
preprocessor-controlled selection, part of the point of having a
standard is to facilitate that, and make it easy and bulletproof.
For example, if C99 features like isnan() are needed, it is very
easy to establish that requirement using a preprocessor test:

    #if __STDC_VERSION__ > 199900
    #else
    #error Sorry, Charlie
    #endif

As for the argument that isnan() cannot be written portably for
pre-C99 environments, what is offered is pure and simple a
strawman argument.  There are at least a couple easy ways to
write a myisnan() function that evaluate nan-ness reliably and do
not suffer from the optimization malady mentioned.  Is the
approach you mentioned the only way you could think of, or did
you just not bother to try exploring alternatives?  Either way,
don't blame how standardization happens for the results of your
own shortcomings.

> But with a function to copy a string to a buffer, taking a length
> for safety, just write one, call it mysafestrcpy(), make it static,
> and then supply it.
>
> The trivial is important, and you can't have programs breaking just
> because of a little string copying routine.

ISTM you have totally missed the point.  The whole reason the
discussion took place is because the current language standard
(even the latest one) does NOT contain a suitable standardized
function for this purpose.  Of course that means writing one.
But the existence of other, lower-level, standard building block
functions makes it almost trivial to do that.  Even if the
standard language does not have exactly what is needed, it pays
to leverage what library functionality it does provide.  The
point of the discussion is identifying good ways to do that.

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


#93805

Fromcross@spitfire.i.gajendra.net (Dan Cross)
Date2016-09-19 15:15 +0000
Message-ID<nrovf5$ou5$1@reader2.panix.com>
In reply to#93568
In article <kfnfup1gdrl.fsf@x-alumni2.alumni.caltech.edu>,
Tim Rentsch  <txr@alumni.caltech.edu> wrote:
>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>> [snip]
>>
>> I'm still not quite sure what application you are referring to.
>> Certainly, for the filesystem thing or similar applications,
>> strncpy() really does do what one wants.
>
>Oh yes, strncpy() does the job it was meant to do very well.
>Now if only more people knew what that job is....

Indeed.  Personally, I think the name, 'fldncpy()' would have
been better: bounded field copy.

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


#93411

FromRichard Damon <Richard@Damon-Family.org>
Date2016-09-13 08:19 -0400
Message-ID<99SBz.71132$eM3.39366@fx04.iad>
In reply to#93408
On 9/12/16 9:45 PM, Dan Cross wrote:
> 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).
>
All it takes is comparing the last byte of dest to nul (0). Since 
strncpy fills the tail with 0, a string that fit will have trailing 
nuls, if it doesn't, there won't be one. Yes, if the 'payload' of the 
string exactly fits, you will consider it 'truncated' but then for a 
standard string, the nul IS part of the string, so it is.

Note, the lack of notification of truncation isn't that surprising as 
that is one of the purposes of the function, to truncate the over length 
string.

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


#93414

Fromcross@spitfire.i.gajendra.net (Dan Cross)
Date2016-09-13 14:07 +0000
Message-ID<nr917m$mpd$1@reader2.panix.com>
In reply to#93411
In article <99SBz.71132$eM3.39366@fx04.iad>,
Richard Damon  <Richard@Damon-Family.org> wrote:
>On 9/12/16 9:45 PM, Dan Cross wrote:
>> 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).
>
>All it takes is comparing the last byte of dest to nul (0). Since 
>strncpy fills the tail with 0, a string that fit will have trailing 
>nuls, if it doesn't, there won't be one. Yes, if the 'payload' of the 
>string exactly fits, you will consider it 'truncated' but then for a 
>standard string, the nul IS part of the string, so it is.

Note I said, "or similar."  Yes, you can do that, but the larger
point I was trying to make is that it must be done as a separate
step.

>Note, the lack of notification of truncation isn't that surprising as 
>that is one of the purposes of the function, to truncate the over length 
>string.

This is subjective, but I disagree.  The function takes an argument
to bound the amount it will copy, but that does not necessarily imply
it shouldn't tell you if it hit that boundary.  Yes, you *can* detect
it after the call, but one can also define a function that lets you
know whether it truncated as in strlcpy().

The other deficiencies of strncpy() are such that it really should
not be used for things other than it's original purpose.

	- Dan C.

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


#93421

Fromsupercat@casperkitty.com
Date2016-09-13 07:57 -0700
Message-ID<fd0e9428-fba4-4863-87f3-f53ae84385b6@googlegroups.com>
In reply to#93414
On Tuesday, September 13, 2016 at 9:07:59 AM UTC-5, Dan Cross wrote:
> The other deficiencies of strncpy() are such that it really should
> not be used for things other than it's original purpose.

Which is writing to fixed-sized zero-padded string buffers which may or
may not have anything to do with directory entries.  While the specific
use for directory entries may be obsolete, the function is still
convenient in places where one is dealing with lots of strings that are
short and precisely fit within an data structure which includes aligned
data items.  For example, if one has a data structure that contains some
64-bit aligned data items and includes an 8-character field, adding a
trailing byte to the field could double the amount of space it requires.
While memcpy() may often be better than strncpy(), it requires strings
that are padded out to the correct length.  If one wanted to populate an
8-character field with "N/A", for example one would need to use

             memcpy(thing->field, "N/A\0\0\0\0", 8);

rather than

             strncpy(thing->field, "N/A", THING_FIELD_SIZE);.

Note that the former version of the code will break if the thing field
size grows, **and using a macro for the size wouldn't help**, while the
latter version will automatically adapt to any increase in field size.

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


#93424

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-13 17:33 +0100
Message-ID<87lgyvpxno.fsf@bsb.me.uk>
In reply to#93421
<snip text on strncpy>
supercat@casperkitty.com writes:
> [...] the function is still
> convenient in places where one is dealing with lots of strings that are
> short and precisely fit within an data structure which includes aligned
> data items.  For example, if one has a data structure that contains some
> 64-bit aligned data items and includes an 8-character field, adding a
> trailing byte to the field could double the amount of space it
> requires.

I would not call these strings.  In fact, I prefer not to call strncpy a
string function.

> While memcpy() may often be better than strncpy(), it requires strings
> that are padded out to the correct length.  If one wanted to populate an
> 8-character field with "N/A", for example one would need to use
>
>              memcpy(thing->field, "N/A\0\0\0\0", 8);

You might consider using

  memcpy(thing->field, (char [sizeof thing->field]){"N/A"}, sizeof thing->field);

since you get the padding and the size automatically.  It can always be
turned into a macro to remove the repetition.

> rather than
>
>              strncpy(thing->field, "N/A", THING_FIELD_SIZE);.

On advantage of memcpy + compound literal is that if you use a string
literal that is too long, you will most likely get a message from the
compiler.  The strncpy won't go wrong, of course, but a string longer
than THING_FIELD_SIZE is almost certainly a programmer error you'd like
to know about.

> Note that the former version of the code will break if the thing field
> size grows, **and using a macro for the size wouldn't help**, while the
> latter version will automatically adapt to any increase in field size.

That's the advantage of using a compound literal.

-- 
Ben.

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


#93428

Fromcross@spitfire.i.gajendra.net (Dan Cross)
Date2016-09-13 18:13 +0000
Message-ID<nr9fkh$1vc$1@reader2.panix.com>
In reply to#93424
In article <87lgyvpxno.fsf@bsb.me.uk>,
Ben Bacarisse  <ben.usenet@bsb.me.uk> wrote:
> [snip]
>
>You might consider using
>
>  memcpy(thing->field, (char [sizeof thing->field]){"N/A"}, sizeof thing->field);
>
>since you get the padding and the size automatically.  It can always be
>turned into a macro to remove the repetition.

I was curious about this, as it struck me that a decent compiler
would likely generate the same code for both of these.  For strings
longer than the destination this was more or less true with GCC 5.4
and Clang.  The generated machine code from GCC was identical; in
clang, the compound literal truncates the string data in the text
section.

Interestingly, in the case where the source was NOT longer than
the destination buffer, clang always calls strncpy (though it does
optimize it as a tail call); the memcpy case is optimized to a couple
of load instructions, depending on the destination buffer size.

For non-overflow, GCC optimizes out the calls to both strncpy() and
memcpy().

>> rather than
>>
>>              strncpy(thing->field, "N/A", THING_FIELD_SIZE);.
>
>On advantage of memcpy + compound literal is that if you use a string
>literal that is too long, you will most likely get a message from the
>compiler.  The strncpy won't go wrong, of course, but a string longer
>than THING_FIELD_SIZE is almost certainly a programmer error you'd like
>to know about.

Indeed.  That's a useful diagnostic.  It also generates faster code
on some compilers.

>> Note that the former version of the code will break if the thing field
>> size grows, **and using a macro for the size wouldn't help**, while the
>> latter version will automatically adapt to any increase in field size.
>
>That's the advantage of using a compound literal.

	- Dan C.

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


#93431

Fromsupercat@casperkitty.com
Date2016-09-13 11:30 -0700
Message-ID<04886746-5004-45fd-98c2-899ea58972f8@googlegroups.com>
In reply to#93424
On Tuesday, September 13, 2016 at 11:33:41 AM UTC-5, Ben Bacarisse wrote:
> I would not call these strings.  In fact, I prefer not to call strncpy a
> string function.

I would call them "zero-padded" strings.  If one is interacting with APIs
that describe various representations for sequences of characters as
different kinds of strings (e.g. a Pascal string, a zero-padded string, etc.)
I don't think using some noun other than "string" is helpful.  I agree that
in the absence of context to indicate otherwise, the noun "string" usually
means "C string", but that doesn't mean that the noun "string" should not
be part of the name of other kinds.

> You might consider using
> 
>   memcpy(thing->field, (char [sizeof thing->field]){"N/A"}, sizeof thing->field);
> 
> since you get the padding and the size automatically.  It can always be
> turned into a macro to remove the repetition.

Such an approach might be good if C supported static constant compound
literals.  Can you identify any implementations where your version would
not end up producing substantially bulkier code than the strncpy version?

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


#93439

Fromcross@spitfire.i.gajendra.net (Dan Cross)
Date2016-09-13 20:03 +0000
Message-ID<nr9m2k$899$1@reader2.panix.com>
In reply to#93431
In article <04886746-5004-45fd-98c2-899ea58972f8@googlegroups.com>,
 <supercat@casperkitty.com> wrote:
>On Tuesday, September 13, 2016 at 11:33:41 AM UTC-5, Ben Bacarisse wrote:
>> I would not call these strings.  In fact, I prefer not to call strncpy a
>> string function.
>
>I would call them "zero-padded" strings.  If one is interacting with APIs
>that describe various representations for sequences of characters as
>different kinds of strings (e.g. a Pascal string, a zero-padded string, etc.)
>I don't think using some noun other than "string" is helpful.  I agree that
>in the absence of context to indicate otherwise, the noun "string" usually
>means "C string", but that doesn't mean that the noun "string" should not
>be part of the name of other kinds.

I would call this "textual data" or a "text buffer" or similar.  "string"
is too overloaded of a term to not cause confusion with C strings and their
semantics.

>> You might consider using
>> 
>>   memcpy(thing->field, (char [sizeof thing->field]){"N/A"}, sizeof thing->field);
>> 
>> since you get the padding and the size automatically.  It can always be
>> turned into a macro to remove the repetition.
>
>Such an approach might be good if C supported static constant compound
>literals.  Can you identify any implementations where your version would
>not end up producing substantially bulkier code than the strncpy version?

As I mentioned earlier, GCC 5.4 generates the same machine code for both
the strncpy() and memcpy()+compound literal variants.  Clang 3.7 calls
strncpy() but optimizes out the call to memcpy().  So not only are there
at least two platforms where the generated code is less bulky than the
strncpy() version, on at least one of those it is somewhat even lighter.

	- Dan C.

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


#93440

Fromsupercat@casperkitty.com
Date2016-09-13 13:38 -0700
Message-ID<8b37afbd-a536-4d35-ac35-2cec84d0a0f3@googlegroups.com>
In reply to#93439
On Tuesday, September 13, 2016 at 3:03:40 PM UTC-5, Dan Cross wrote:
> As I mentioned earlier, GCC 5.4 generates the same machine code for both
> the strncpy() and memcpy()+compound literal variants.  Clang 3.7 calls
> strncpy() but optimizes out the call to memcpy().  So not only are there
> at least two platforms where the generated code is less bulky than the
> strncpy() version, on at least one of those it is somewhat even lighter.

That's curious; the code generation of 6.2 seems to be a step backward there.
Given

    #define MSG_SIZE 12
    void test(char *dest)
    {
      memcpy(dest,(char[MSG_SIZE]){"Test"}, MSG_SIZE);
    }

The 86-64 GCC 6.2 on godbolt.org wrote out 12 consecutive single-byte
move instructions; if the size were increased to the point where in-
line expansion would become impractical (e.g. 256) it seems to create
a temporary array on the stack though it only subtract 136 from SP, which
I find odd.

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


#93443

Fromcross@spitfire.i.gajendra.net (Dan Cross)
Date2016-09-13 21:39 +0000
Message-ID<nr9rmf$kaf$1@reader2.panix.com>
In reply to#93440
In article <8b37afbd-a536-4d35-ac35-2cec84d0a0f3@googlegroups.com>,
 <supercat@casperkitty.com> wrote:
>On Tuesday, September 13, 2016 at 3:03:40 PM UTC-5, Dan Cross wrote:
>> As I mentioned earlier, GCC 5.4 generates the same machine code for both
>> the strncpy() and memcpy()+compound literal variants.  Clang 3.7 calls
>> strncpy() but optimizes out the call to memcpy().  So not only are there
>> at least two platforms where the generated code is less bulky than the
>> strncpy() version, on at least one of those it is somewhat even lighter.
>
>That's curious; the code generation of 6.2 seems to be a step backward there.
>Given
>
>    #define MSG_SIZE 12
>    void test(char *dest)
>    {
>      memcpy(dest,(char[MSG_SIZE]){"Test"}, MSG_SIZE);
>    }
>
>The 86-64 GCC 6.2 on godbolt.org wrote out 12 consecutive single-byte
>move instructions; if the size were increased to the point where in-
>line expansion would become impractical (e.g. 256) it seems to create
>a temporary array on the stack though it only subtract 136 from SP, which
>I find odd.

Interesting.  I wrote it for arm64 and ran it against gcc 6.1, which
is the most recent compiler I have on my dev machine for the aarch64
port of the Harvey OS.  On that platform, the strncpy() version emits
a call to strncpy(), as on x86 with Clang, while your code optimizes
out the call to memcpy() and emits four moves and twelve STRB instructions
(this makes sense as presumably the function in question doesn't know
the alignment of `dest` at compile time).

Somewhat more surprising to me was that if I changed the code to write
into e.g. a global variable and I changed the type of that to be e.g.
an int, one still sees the same number of single-byte loads.  I would
have expected the compiler to recognize that these were aligned and
load registers with constants containing more than a single byte of
text, and then write to memory with word-storing instructions.

	- Dan C.

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


#93447

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-13 23:26 +0100
Message-ID<87a8fbphbw.fsf@bsb.me.uk>
In reply to#93431
supercat@casperkitty.com writes:

> On Tuesday, September 13, 2016 at 11:33:41 AM UTC-5, Ben Bacarisse wrote:
<snip>
>> You might consider using
>> 
>>   memcpy(thing->field, (char [sizeof thing->field]){"N/A"}, sizeof thing->field);
>> 
>> since you get the padding and the size automatically.  It can always be
>> turned into a macro to remove the repetition.
>
> Such an approach might be good if C supported static constant compound
> literals.  Can you identify any implementations where your version would
> not end up producing substantially bulkier code than the strncpy version?

Yes.  The gcc I have here (5.2.1) compiles

  struct S { char field[8]; };
   
  void f(struct S *thing)
  {
       memcpy(thing->field, (char [sizeof thing->field]){"N/A"},
              sizeof thing->field);
  }

to just

        movq    $4271950, (%rdi)
        ret

using -O2.

-- 
Ben.

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


#93451

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-09-13 16:14 -0700
Message-ID<kfnzinbie9d.fsf@x-alumni2.alumni.caltech.edu>
In reply to#93424
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

> <snip text on strncpy>
> supercat@casperkitty.com writes:
>> [...] 
>> While memcpy() may often be better than strncpy(), it requires strings
>> that are padded out to the correct length.  If one wanted to populate an
>> 8-character field with "N/A", for example one would need to use
>>
>>              memcpy(thing->field, "N/A\0\0\0\0", 8);
>
> You might consider using
>
>   memcpy(thing->field, (char [sizeof thing->field]){"N/A"}, sizeof thing->field);
>
> since you get the padding and the size automatically.  It can always be
> turned into a macro to remove the repetition.

This technique using a compound literal is a nice one to know.
One caution though:  it doesn't work when the array bound is
not a constant expression.

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


#93422

FromBartC <bc@freeuk.com>
Date2016-09-13 15:59 +0100
Message-ID<nr948u$rbv$1@dont-email.me>
In reply to#93408
On 13/09/2016 02:45, Dan Cross wrote:

> 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

That's handy to do anyway, whether you're going to write to disk or not.

For example, for making full use of small char-arrays within structs. 
Then, if you only have a 4-char field, you want to be able to use all 4 
chars, instead of needing an odd 5-char field or being limited to an odd 
3-char string.

Nothing to do with the subject (and I just fancied writing some C), but 
the following code uses store- and get- functions for copying normal 
terminated strings into packed strings and extracting them again.

But it stores them as counted strings (storing a length within the 
packed string without sacrificing a byte, or a top bit, to do so.).

Truncation is reported (only because it was mentioned in the 
sub-thread!). However unused characters within the field are not zeroed.


#include<stdio.h>
#include<string.h>

void setfslength(char* s, int m, int n){
// encode length n of packed string within m-char field, within
// last two bytes of field. Strings can be up to m characters so
// using the entire field.
// a,b  The last two chars of the fixed string
// ---
// 0,N	Length is N
// 0,0	Length is 0 (special case of 0,N)
// X,0	Length is M-1
// X,Y	Length is M
// NOTE: this only works for m in 2..256, and the string can't
// contain zero bytes.

     if (m == n);            // x,y
     else if (n == m-1)
     	*(s+m-1) = 0;    // x,0
     else {               // 0,n
     	*(s+m-2) = 0;
     	*(s+m-1) = n;
     }
}

int getfslength(char* s, int m) {
// s points to a packed string encoded with length at its end.
// m is the max length (m>=2)
// return the encoded length

     s += m-1;

     if (*(s-1) == 0)
     	return *s;
     else if (*s == 0)
     	return m-1;
     else
     	return m;
}

int storepackedstring(char* dest, int width, char* source) {
// store C string into packed fixed-length non-nul-terminated
// field of size 'width' chars.
// return 1 (OK), 0 (truncated)
// width must be 2 to 256

     int slen = strlen(source);
     int status;

     if (slen>width) {
         status = 0;
         slen = width;
     }
     else
         status = 1;

     if (slen)
         memcpy(dest,source,slen);

     setfslength(dest,width,slen);
     return status;
}

int getpackedstring(char* dest, int width, char* source) {
// copy packed string in fixed width field to normal C terminated
// string. dest must point to at least width+1 characters (but
// maximum space needed is 257 characters).
// returns length of packed string

     int slen = getfslength(source, width);

     if (slen)
         memcpy(dest,source,slen);
     *(dest+slen) = 0;
     return slen;
}

int main(void) {

     typedef struct {
         char A[4];
         char B[2];
         char C[26];
     } R;

     R S;
     char str[257];
     int len;
     #define STR1 "bartc"
     #define STR2 "XY"
     #define STR3 "ABC"

     if (!storepackedstring(S.A, sizeof S.A, STR1))
         printf("%s truncated\n",STR1);

     if (!storepackedstring(S.B, sizeof S.B, STR2))
         printf("%s truncated\n",STR2);

     if (!storepackedstring(S.C, sizeof S.C, STR3))
         printf("%s truncated\n",STR3);

     len = getpackedstring(str, sizeof S.A, S.A);
     printf("S.A = %s Length: %d\n", str, len);

     len = getpackedstring(str, sizeof S.B, S.B);
     printf("S.B = %s Length: %d\n", str, len);

     len = getpackedstring(str, sizeof S.C, S.C);
     printf("S.C = %s Length: %d\n", str, len);

}


-- 
Bartc

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


#93450

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-09-13 16:07 -0700
Message-ID<kfn4m5jjt5b.fsf@x-alumni2.alumni.caltech.edu>
In reply to#93408
cross@spitfire.i.gajendra.net (Dan Cross) writes:

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

I'm curious - did you really mean ersatz?  The code doesn't
look that ersatz to me.  :)

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


#93455

Fromcross@spitfire.i.gajendra.net (Dan Cross)
Date2016-09-14 00:24 +0000
Message-ID<nra5c3$360$1@reader2.panix.com>
In reply to#93450
In article <kfn4m5jjt5b.fsf@x-alumni2.alumni.caltech.edu>,
Tim Rentsch  <txr@alumni.caltech.edu> wrote:
>cross@spitfire.i.gajendra.net (Dan Cross) writes:
>
>> An ersatz implementation of strlcpy() taken from
>> http://pub.gajendra.net/src/strlcpy.c is:  [...]
>
>I'm curious - did you really mean ersatz?  The code doesn't
>look that ersatz to me.  :)

Thanks.  Perhaps I should have said "bespoke" but I'm not
quite that much of a hipster. :-)

	- Dan C.

[toc] | [prev] | [standalone]


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

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


csiph-web