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


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

Automatic strings without malloc

Started bypozz <pozzugno@gmail.com>
First post2021-11-17 11:36 +0100
Last post2021-11-20 20:49 -0800
Articles 20 on this page of 48 — 16 participants

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


Contents

  Automatic strings without malloc pozz <pozzugno@gmail.com> - 2021-11-17 11:36 +0100
    Re: Automatic strings without malloc pozz <pozzugno@gmail.com> - 2021-11-17 11:38 +0100
    Re: Automatic strings without malloc Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-11-17 03:00 -0800
    Re: Automatic strings without malloc David Brown <david.brown@hesbynett.no> - 2021-11-17 12:04 +0100
      Re: Automatic strings without malloc Manfred <noname@add.invalid> - 2021-11-17 18:19 +0100
        Re: Automatic strings without malloc David Brown <david.brown@hesbynett.no> - 2021-11-17 20:34 +0100
      Re: Automatic strings without malloc pozz <pozzugno@gmail.com> - 2021-11-18 10:07 +0100
    Re: Automatic strings without malloc Thiago Adams <thiago.adams@gmail.com> - 2021-11-17 05:11 -0800
      Re: Automatic strings without malloc Philipp Klaus Krause <pkk@spth.de> - 2021-11-18 15:29 +0100
    Re: Automatic strings without malloc Bart <bc@freeuk.com> - 2021-11-17 13:47 +0000
    Re: Automatic strings without malloc scott@slp53.sl.home (Scott Lurndal) - 2021-11-17 15:34 +0000
      Re: Automatic strings without malloc Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-11-17 07:36 -0800
        Re: Automatic strings without malloc David Brown <david.brown@hesbynett.no> - 2021-11-17 16:56 +0100
          Re: Automatic strings without malloc scott@slp53.sl.home (Scott Lurndal) - 2021-11-17 18:21 +0000
            Re: Automatic strings without malloc David Brown <david.brown@hesbynett.no> - 2021-11-17 20:37 +0100
              Re: Automatic strings without malloc scott@slp53.sl.home (Scott Lurndal) - 2021-11-17 21:35 +0000
                Re: Automatic strings without malloc Thiago Adams <thiago.adams@gmail.com> - 2021-11-19 05:38 -0800
                  Re: Automatic strings without malloc Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-11-19 07:13 -0800
              Re: Automatic strings without malloc William Ahern <william@25thandClement.com> - 2021-11-17 20:46 -0800
                Re: Automatic strings without malloc David Brown <david.brown@hesbynett.no> - 2021-11-18 10:50 +0100
                  Re: Automatic strings without malloc Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-11-18 03:56 -0800
                    Re: Automatic strings without malloc Thiago Adams <thiago.adams@gmail.com> - 2021-11-18 05:54 -0800
                      Re: Automatic strings without malloc Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-11-18 16:38 +0000
                        Re: Automatic strings without malloc Thiago Adams <thiago.adams@gmail.com> - 2021-11-18 10:52 -0800
                          Re: Automatic strings without malloc Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-11-18 11:27 -0800
                          Re: Automatic strings without malloc Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-11-18 20:41 +0000
                    Re: Automatic strings without malloc David Brown <david.brown@hesbynett.no> - 2021-11-18 16:05 +0100
          Re: Automatic strings without malloc Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-11-17 11:22 -0800
            Re: Automatic strings without malloc David Brown <david.brown@hesbynett.no> - 2021-11-17 20:39 +0100
              Re: Automatic strings without malloc Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-11-17 15:18 -0800
                [OT] Generally... [Was: Automatic strings without malloc] Jeremy Brubaker <jbrubake@orionarts.invalid> - 2021-11-18 17:46 +0000
                  Re: [OT] Generally... [Was: Automatic strings without malloc] Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-11-18 11:21 -0800
    Re: Automatic strings without malloc Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-11-17 11:14 -0800
      Re: Automatic strings without malloc pozz <pozzugno@gmail.com> - 2021-11-18 10:08 +0100
    Re: Automatic strings without malloc Siri Cruise <chine.bleu@yahoo.com> - 2021-11-18 12:25 -0800
      Re: Automatic strings without malloc David Brown <david.brown@hesbynett.no> - 2021-11-18 23:19 +0100
        Re: Automatic strings without malloc Siri Cruise <chine.bleu@yahoo.com> - 2021-11-18 17:22 -0800
          Re: Automatic strings without malloc Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-11-19 01:46 -0800
            Re: Automatic strings without malloc David Brown <david.brown@hesbynett.no> - 2021-11-19 17:29 +0100
          Re: Automatic strings without malloc David Brown <david.brown@hesbynett.no> - 2021-11-19 17:26 +0100
            Re: Automatic strings without malloc Siri Cruise <chine.bleu@yahoo.com> - 2021-11-19 09:00 -0800
              Re: Automatic strings without malloc David Brown <david.brown@hesbynett.no> - 2021-11-19 18:25 +0100
                Re: Automatic strings without malloc "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-11-19 14:58 -0800
              Re: Automatic strings without malloc Guillaume <message@bottle.org> - 2021-11-19 19:37 +0100
            Re: Automatic strings without malloc "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-11-19 12:34 -0800
              Re: Automatic strings without malloc Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-11-19 13:44 -0800
                Re: Automatic strings without malloc David Brown <david.brown@hesbynett.no> - 2021-11-20 13:30 +0100
                  Re: Automatic strings without malloc luser droog <luser.droog@gmail.com> - 2021-11-20 20:49 -0800

Page 1 of 3  [1] 2 3  Next page →


#163436 — Automatic strings without malloc

Frompozz <pozzugno@gmail.com>
Date2021-11-17 11:36 +0100
SubjectAutomatic strings without malloc
Message-ID<sn2lvp$sl7$1@dont-email.me>
Many times I need to construct a string through a call to sprintf and 
pass it to an external function.

   char s[32];
   sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year);
   lcd_write(s);

The size of s is fixed and calculated for the maximum length of 
yourname, that is 9.

Later in time, I need to change the message into:

   sprintf(s, "Hello %s, today is %d/%d/%d", yourname, day, month, year);

Of course, I need to re-calculate the worst-case length, that should be 
now 35. However this is error-prone and I could forget to change the 
size of array.

Is there a better way to manage this situation? I can't use malloc() 
because I'm on an embedded system where I can't use heap.

I'm thinking to use sprintf(NULL, ...), such as:

   const char fmt[] = "Hi %s, today is %d/%d/%d";
   size_t n = sprintf(NULL, fmt, yourname, day, month, year);
   char s[n + 1];
   sprintf(s, fmt, yourname, day, month, year);
   lcd_write(s);

[toc] | [next] | [standalone]


#163437

Frompozz <pozzugno@gmail.com>
Date2021-11-17 11:38 +0100
Message-ID<sn2m28$sl7$2@dont-email.me>
In reply to#163436
Il 17/11/2021 11:36, pozz ha scritto:
> Many times I need to construct a string through a call to sprintf and 
> pass it to an external function.
> 
>    char s[32];
>    sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year);
>    lcd_write(s);
> 
> The size of s is fixed and calculated for the maximum length of 
> yourname, that is 9.
> 
> Later in time, I need to change the message into:
> 
>    sprintf(s, "Hello %s, today is %d/%d/%d", yourname, day, month, year);
> 
> Of course, I need to re-calculate the worst-case length, that should be 
> now 35. However this is error-prone and I could forget to change the 
> size of array.
> 
> Is there a better way to manage this situation? I can't use malloc() 
> because I'm on an embedded system where I can't use heap.
> 
> I'm thinking to use sprintf(NULL, ...), such as:

I'm sorry, I mean:

   snprintf(NULL, 0, ...)

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


#163438

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2021-11-17 03:00 -0800
Message-ID<e44ba99b-496e-4b83-bc81-1e16b18639d1n@googlegroups.com>
In reply to#163436
On Wednesday, 17 November 2021 at 10:36:53 UTC, pozz wrote:
> Many times I need to construct a string through a call to sprintf and 
> pass it to an external function. 
> 
> char s[32]; 
> sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year); 
> lcd_write(s); 
> 
> The size of s is fixed and calculated for the maximum length of 
> yourname, that is 9. 
> 
> Later in time, I need to change the message into: 
> 
> sprintf(s, "Hello %s, today is %d/%d/%d", yourname, day, month, year); 
> 
> Of course, I need to re-calculate the worst-case length, that should be 
> now 35. However this is error-prone and I could forget to change the 
> size of array. 
> 
> Is there a better way to manage this situation? I can't use malloc() 
> because I'm on an embedded system where I can't use heap. 
> 
> I'm thinking to use sprintf(NULL, ...), such as: 
> 
> const char fmt[] = "Hi %s, today is %d/%d/%d"; 
> size_t n = sprintf(NULL, fmt, yourname, day, month, year); 
> char s[n + 1]; 
> sprintf(s, fmt, yourname, day, month, year); 
> lcd_write(s);
>
That's a reasonable solution, as long as you know you have enough stack
(and a C99 compiler).
You've got to ask how likely it is that a bug whereby you overrun the buffer
will persist. If a bug will be caught in the first informal test, then it's not
dangerous. If it could slip through until a late stage, it's more worrying.
Since a buffer overrun will corrupt the variable immediately after the 
buffer in memory, this might be detected immediately, or it might not be detected
for some time, depending on what that variable is used for. So a dangerous
bug, unless you've got some memory-checking software that can detect
such situations.
That's your best answer, however the software might be very expensive, or
might not be available at all. 

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


#163439

FromDavid Brown <david.brown@hesbynett.no>
Date2021-11-17 12:04 +0100
Message-ID<sn2nk2$7mp$1@dont-email.me>
In reply to#163436
On 17/11/2021 11:36, pozz wrote:
> Many times I need to construct a string through a call to sprintf and
> pass it to an external function.
> 
>   char s[32];
>   sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year);
>   lcd_write(s);
> 
> The size of s is fixed and calculated for the maximum length of
> yourname, that is 9.
> 
> Later in time, I need to change the message into:
> 
>   sprintf(s, "Hello %s, today is %d/%d/%d", yourname, day, month, year);
> 
> Of course, I need to re-calculate the worst-case length, that should be
> now 35. However this is error-prone and I could forget to change the
> size of array.
> 
> Is there a better way to manage this situation? I can't use malloc()
> because I'm on an embedded system where I can't use heap.
> 
> I'm thinking to use sprintf(NULL, ...), such as:
> 
>   const char fmt[] = "Hi %s, today is %d/%d/%d";
>   size_t n = sprintf(NULL, fmt, yourname, day, month, year);
>   char s[n + 1];
>   sprintf(s, fmt, yourname, day, month, year);
>   lcd_write(s);
> 

That would work (with your follow-up correction).  You might want to put
a limit on "n" to avoid accidental stack overflow.  This arrangement
does mean that you are doing the printf part twice.

Very often in small systems you know there is a maximum size - if your
screen is 40 characters wide, then 40 characters is enough in your
array.  And if you might need up to 40 characters then you might as well
use all of the 40 chars, even though your string might be shorter - you
really don't want to test your code for the name "Al" on date 1/2/2021
and then find you have a stack overflow on 10/10/2021 with the name
"Rhoshandiatellyneshiaunneveshenk".  (Apparently that's a real name -
according to google!)


It is also worth noting that only one task should be calling lcd_write
at a time - otherwise your display will be messed up.  You can extend
that and say that only one task will be using the format buffer at a
time, and then it can be a statically array that is shared by all client
code.


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


#163448

FromManfred <noname@add.invalid>
Date2021-11-17 18:19 +0100
Message-ID<sn3dim$1li1$1@gioia.aioe.org>
In reply to#163439
On 11/17/2021 12:04 PM, David Brown wrote:
> On 17/11/2021 11:36, pozz wrote:
>> Many times I need to construct a string through a call to sprintf and
>> pass it to an external function.
>>
>>    char s[32];
>>    sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year);
>>    lcd_write(s);
>>
>> The size of s is fixed and calculated for the maximum length of
>> yourname, that is 9.
>>
>> Later in time, I need to change the message into:
>>
>>    sprintf(s, "Hello %s, today is %d/%d/%d", yourname, day, month, year);
>>
>> Of course, I need to re-calculate the worst-case length, that should be
>> now 35. However this is error-prone and I could forget to change the
>> size of array.
>>
>> Is there a better way to manage this situation? I can't use malloc()
>> because I'm on an embedded system where I can't use heap.
>>
>> I'm thinking to use sprintf(NULL, ...), such as:
>>
>>    const char fmt[] = "Hi %s, today is %d/%d/%d";
>>    size_t n = sprintf(NULL, fmt, yourname, day, month, year);
>>    char s[n + 1];
>>    sprintf(s, fmt, yourname, day, month, year);
>>    lcd_write(s);
>>
> 
> That would work (with your follow-up correction).  You might want to put
> a limit on "n" to avoid accidental stack overflow.  This arrangement
> does mean that you are doing the printf part twice.
> 
> Very often in small systems you know there is a maximum size - if your
> screen is 40 characters wide, then 40 characters is enough in your
> array.  And if you might need up to 40 characters then you might as well
> use all of the 40 chars, even though your string might be shorter - you
> really don't want to test your code for the name "Al" on date 1/2/2021
> and then find you have a stack overflow on 10/10/2021 with the name
> "Rhoshandiatellyneshiaunneveshenk".  (Apparently that's a real name -
> according to google!)

This sounds like good advice. It makes sense to make use of the 
information given by the maximum string length that can actually be emitted.

I'd add the following:
1) use snprintf instead of sprintf; the former is explicitly designed to 
handle the buffer size limit.
2) use a better format specifier instead of plain "%s" for the string 
argument, e.g. "%2.12s"

Both of the above help preventing buffer overflow, which is something 
you need to ensure it never happens.

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


#163452

FromDavid Brown <david.brown@hesbynett.no>
Date2021-11-17 20:34 +0100
Message-ID<sn3lgp$qhj$2@dont-email.me>
In reply to#163448
On 17/11/2021 18:19, Manfred wrote:
> On 11/17/2021 12:04 PM, David Brown wrote:
>> On 17/11/2021 11:36, pozz wrote:
>>> Many times I need to construct a string through a call to sprintf and
>>> pass it to an external function.
>>>
>>>    char s[32];
>>>    sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year);
>>>    lcd_write(s);
>>>
>>> The size of s is fixed and calculated for the maximum length of
>>> yourname, that is 9.
>>>
>>> Later in time, I need to change the message into:
>>>
>>>    sprintf(s, "Hello %s, today is %d/%d/%d", yourname, day, month,
>>> year);
>>>
>>> Of course, I need to re-calculate the worst-case length, that should be
>>> now 35. However this is error-prone and I could forget to change the
>>> size of array.
>>>
>>> Is there a better way to manage this situation? I can't use malloc()
>>> because I'm on an embedded system where I can't use heap.
>>>
>>> I'm thinking to use sprintf(NULL, ...), such as:
>>>
>>>    const char fmt[] = "Hi %s, today is %d/%d/%d";
>>>    size_t n = sprintf(NULL, fmt, yourname, day, month, year);
>>>    char s[n + 1];
>>>    sprintf(s, fmt, yourname, day, month, year);
>>>    lcd_write(s);
>>>
>>
>> That would work (with your follow-up correction).  You might want to put
>> a limit on "n" to avoid accidental stack overflow.  This arrangement
>> does mean that you are doing the printf part twice.
>>
>> Very often in small systems you know there is a maximum size - if your
>> screen is 40 characters wide, then 40 characters is enough in your
>> array.  And if you might need up to 40 characters then you might as well
>> use all of the 40 chars, even though your string might be shorter - you
>> really don't want to test your code for the name "Al" on date 1/2/2021
>> and then find you have a stack overflow on 10/10/2021 with the name
>> "Rhoshandiatellyneshiaunneveshenk".  (Apparently that's a real name -
>> according to google!)
> 
> This sounds like good advice. It makes sense to make use of the
> information given by the maximum string length that can actually be
> emitted.
> 
> I'd add the following:
> 1) use snprintf instead of sprintf; the former is explicitly designed to
> handle the buffer size limit.

Of course.  The OP corrected himself with a follow-up to use snprintf, I
believe.

> 2) use a better format specifier instead of plain "%s" for the string
> argument, e.g. "%2.12s"

That is a possibility, but often %s is fine (with the limit you have
from snprintf).

> 
> Both of the above help preventing buffer overflow, which is something
> you need to ensure it never happens.

Indeed.

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


#163462

Frompozz <pozzugno@gmail.com>
Date2021-11-18 10:07 +0100
Message-ID<sn555a$cjo$1@dont-email.me>
In reply to#163439
Il 17/11/2021 12:04, David Brown ha scritto:
> On 17/11/2021 11:36, pozz wrote:
>> Many times I need to construct a string through a call to sprintf and
>> pass it to an external function.
>>
>>    char s[32];
>>    sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year);
>>    lcd_write(s);
>>
>> The size of s is fixed and calculated for the maximum length of
>> yourname, that is 9.
>>
>> Later in time, I need to change the message into:
>>
>>    sprintf(s, "Hello %s, today is %d/%d/%d", yourname, day, month, year);
>>
>> Of course, I need to re-calculate the worst-case length, that should be
>> now 35. However this is error-prone and I could forget to change the
>> size of array.
>>
>> Is there a better way to manage this situation? I can't use malloc()
>> because I'm on an embedded system where I can't use heap.
>>
>> I'm thinking to use sprintf(NULL, ...), such as:
>>
>>    const char fmt[] = "Hi %s, today is %d/%d/%d";
>>    size_t n = sprintf(NULL, fmt, yourname, day, month, year);
>>    char s[n + 1];
>>    sprintf(s, fmt, yourname, day, month, year);
>>    lcd_write(s);
>>
> 
> That would work (with your follow-up correction).  You might want to put
> a limit on "n" to avoid accidental stack overflow.  This arrangement
> does mean that you are doing the printf part twice.

I know, this is a drawback.


> Very often in small systems you know there is a maximum size - if your
> screen is 40 characters wide, then 40 characters is enough in your
> array.  And if you might need up to 40 characters then you might as well
> use all of the 40 chars, even though your string might be shorter - you
> really don't want to test your code for the name "Al" on date 1/2/2021
> and then find you have a stack overflow on 10/10/2021 with the name
> "Rhoshandiatellyneshiaunneveshenk".  (Apparently that's a real name -
> according to google!)

The example was general, because this is a problem I often have: compose 
a string now to pass to a function.

For LCD example, if you use a variable-width font, it's difficult to 
calc the maximum chars. It depends how many 'i's are in the string.
You could consider the worst case of a string composed by all 'i's...

> It is also worth noting that only one task should be calling lcd_write
> at a time - otherwise your display will be messed up.  You can extend
> that and say that only one task will be using the format buffer at a
> time, and then it can be a statically array that is shared by all client
> code.

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


#163441

FromThiago Adams <thiago.adams@gmail.com>
Date2021-11-17 05:11 -0800
Message-ID<8ae929dc-6b89-4a30-bbb0-16ceaeb94c63n@googlegroups.com>
In reply to#163436
On Wednesday, November 17, 2021 at 7:36:53 AM UTC-3, pozz wrote:
> Many times I need to construct a string through a call to sprintf and 
> pass it to an external function. 
> 
> char s[32]; 
> sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year); 
> lcd_write(s); 
> 
> The size of s is fixed and calculated for the maximum length of 
> yourname, that is 9. 
> 
> Later in time, I need to change the message into: 
> 
> sprintf(s, "Hello %s, today is %d/%d/%d", yourname, day, month, year); 
> 
> Of course, I need to re-calculate the worst-case length, that should be 
> now 35. However this is error-prone and I could forget to change the 
> size of array. 
> 
> Is there a better way to manage this situation? I can't use malloc() 
> because I'm on an embedded system where I can't use heap. 
> 
> I'm thinking to use sprintf(NULL, ...), such as: 
> 
> const char fmt[] = "Hi %s, today is %d/%d/%d"; 
> size_t n = sprintf(NULL, fmt, yourname, day, month, year); 
> char s[n + 1]; 
> sprintf(s, fmt, yourname, day, month, year); 
> lcd_write(s);

See : asprintf
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1248.pdf

This function is not implemented in some systems but it can be 
built with other printf functions.

There is also open_memstream that I wish were part of C standard
because It cannot be implemented on windows without access to FILE internals.
https://linux.die.net/man/3/open_memstream

I create my own memory stream to be possible to use on windows and linux.

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


#163468

FromPhilipp Klaus Krause <pkk@spth.de>
Date2021-11-18 15:29 +0100
Message-ID<sn5o0j$f35$1@solani.org>
In reply to#163441
Am 17.11.21 um 14:11 schrieb Thiago Adams:
> 
> See : asprintf
> http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1248.pdf

asprintf allocates on the heap "as if by malloc", so if he can't use
malloc, he can't use asprintf.

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


#163442

FromBart <bc@freeuk.com>
Date2021-11-17 13:47 +0000
Message-ID<sn315u$qj7$1@dont-email.me>
In reply to#163436
On 17/11/2021 10:36, pozz wrote:
> Many times I need to construct a string through a call to sprintf and 
> pass it to an external function.
> 
>    char s[32];
>    sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year);
>    lcd_write(s);
> 
> The size of s is fixed and calculated for the maximum length of 
> yourname, that is 9.
> 
> Later in time, I need to change the message into:
> 
>    sprintf(s, "Hello %s, today is %d/%d/%d", yourname, day, month, year);
> 
> Of course, I need to re-calculate the worst-case length, that should be 
> now 35. However this is error-prone and I could forget to change the 
> size of array.
> 
> Is there a better way to manage this situation? I can't use malloc() 
> because I'm on an embedded system where I can't use heap.
> 
> I'm thinking to use sprintf(NULL, ...), such as:
> 
>    const char fmt[] = "Hi %s, today is %d/%d/%d";
>    size_t n = sprintf(NULL, fmt, yourname, day, month, year);
>    char s[n + 1];
>    sprintf(s, fmt, yourname, day, month, year);
>    lcd_write(s);
> 

Does lcd_write() remember where it was up to? If so you can break it up:

   lcd_write("Hi ");
   lcd_write(yourname);
   lcd_write(", today is ");

This then only leaves the date, which has a maximum width, eg, 
"dd/mm/yyyy". You could also then use a common routine for turning a 
date into a string, if it's needed in a few places.

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


#163445

Fromscott@slp53.sl.home (Scott Lurndal)
Date2021-11-17 15:34 +0000
Message-ID<ei9lJ.146291$I%1.54591@fx36.iad>
In reply to#163436
pozz <pozzugno@gmail.com> writes:
>Many times I need to construct a string through a call to sprintf and 
>pass it to an external function.
>
>   char s[32];
>   sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year);
>   lcd_write(s);

One might consider using 'snprintf' instead of 'sprintf'; it is a bit safer.

I generally always reserve enough space for the largest possible
legal string, particularly when the buffer is on the stack and is
less than a page (4KB) in size.

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


#163446

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2021-11-17 07:36 -0800
Message-ID<24d7df90-3564-407a-999f-a33e774897c5n@googlegroups.com>
In reply to#163445
On Wednesday, 17 November 2021 at 15:34:50 UTC, Scott Lurndal wrote:
> pozz <pozz...@gmail.com> writes: 
> >Many times I need to construct a string through a call to sprintf and 
> >pass it to an external function. 
> > 
> > char s[32]; 
> > sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year); 
> > lcd_write(s);
> One might consider using 'snprintf' instead of 'sprintf'; it is a bit safer. 
> 
It depends whether wrong results are better or worse than no results.

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


#163447

FromDavid Brown <david.brown@hesbynett.no>
Date2021-11-17 16:56 +0100
Message-ID<sn38n4$l8i$1@dont-email.me>
In reply to#163446
On 17/11/2021 16:36, Malcolm McLean wrote:
> On Wednesday, 17 November 2021 at 15:34:50 UTC, Scott Lurndal wrote:
>> pozz <pozz...@gmail.com> writes: 
>>> Many times I need to construct a string through a call to sprintf and 
>>> pass it to an external function. 
>>>
>>> char s[32]; 
>>> sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year); 
>>> lcd_write(s);
>> One might consider using 'snprintf' instead of 'sprintf'; it is a bit safer. 
>>
> It depends whether wrong results are better or worse than no results.
> 

Generally, a truncated string on the output is better than a stack
overflow with your embedded system crashing or going wild.  But your
needs may vary.

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


#163449

Fromscott@slp53.sl.home (Scott Lurndal)
Date2021-11-17 18:21 +0000
Message-ID<9LblJ.45928$SW5.10995@fx45.iad>
In reply to#163447
David Brown <david.brown@hesbynett.no> writes:
>On 17/11/2021 16:36, Malcolm McLean wrote:
>> On Wednesday, 17 November 2021 at 15:34:50 UTC, Scott Lurndal wrote:
>>> pozz <pozz...@gmail.com> writes: 
>>>> Many times I need to construct a string through a call to sprintf and 
>>>> pass it to an external function. 
>>>>
>>>> char s[32]; 
>>>> sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year); 
>>>> lcd_write(s);
>>> One might consider using 'snprintf' instead of 'sprintf'; it is a bit safer. 
>>>
>> It depends whether wrong results are better or worse than no results.
>> 
>
>Generally, a truncated string on the output is better than a stack
>overflow with your embedded system crashing or going wild.  But your
>needs may vary.

Indeed.  Plus a good programmer checks the return value from snprintf.
Always.

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


#163453

FromDavid Brown <david.brown@hesbynett.no>
Date2021-11-17 20:37 +0100
Message-ID<sn3llm$qhj$3@dont-email.me>
In reply to#163449
On 17/11/2021 19:21, Scott Lurndal wrote:
> David Brown <david.brown@hesbynett.no> writes:
>> On 17/11/2021 16:36, Malcolm McLean wrote:
>>> On Wednesday, 17 November 2021 at 15:34:50 UTC, Scott Lurndal wrote:
>>>> pozz <pozz...@gmail.com> writes: 
>>>>> Many times I need to construct a string through a call to sprintf and 
>>>>> pass it to an external function. 
>>>>>
>>>>> char s[32]; 
>>>>> sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year); 
>>>>> lcd_write(s);
>>>> One might consider using 'snprintf' instead of 'sprintf'; it is a bit safer. 
>>>>
>>> It depends whether wrong results are better or worse than no results.
>>>
>>
>> Generally, a truncated string on the output is better than a stack
>> overflow with your embedded system crashing or going wild.  But your
>> needs may vary.
> 
> Indeed.  Plus a good programmer checks the return value from snprintf.
> Always.
> 

Really?  I never do.  But I make sure my buffers are the right size for
the job - or that it doesn't matter if there is truncation (such as for
log outputs).  I prefer to be sure that my inputs to the function are
correct, than to call the function and check for problems afterwards.
(Different people can have different requirements here - but that's the
way I do it.)

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


#163456

Fromscott@slp53.sl.home (Scott Lurndal)
Date2021-11-17 21:35 +0000
Message-ID<0BelJ.45864$np6.1851@fx46.iad>
In reply to#163453
David Brown <david.brown@hesbynett.no> writes:
>On 17/11/2021 19:21, Scott Lurndal wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>> On 17/11/2021 16:36, Malcolm McLean wrote:
>>>> On Wednesday, 17 November 2021 at 15:34:50 UTC, Scott Lurndal wrote:
>>>>> pozz <pozz...@gmail.com> writes: 
>>>>>> Many times I need to construct a string through a call to sprintf and 
>>>>>> pass it to an external function. 
>>>>>>
>>>>>> char s[32]; 
>>>>>> sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year); 
>>>>>> lcd_write(s);
>>>>> One might consider using 'snprintf' instead of 'sprintf'; it is a bit safer. 
>>>>>
>>>> It depends whether wrong results are better or worse than no results.
>>>>
>>>
>>> Generally, a truncated string on the output is better than a stack
>>> overflow with your embedded system crashing or going wild.  But your
>>> needs may vary.
>> 
>> Indeed.  Plus a good programmer checks the return value from snprintf.
>> Always.
>> 
>
>Really?  I never do.  But I make sure my buffers are the right size for
>the job - or that it doesn't matter if there is truncation (such as for
>log outputs).  I prefer to be sure that my inputs to the function are
>correct, than to call the function and check for problems afterwards.
>(Different people can have different requirements here - but that's the
>way I do it.)
>

I often use snprintf in place of strcat.  For that purpose, checking the return
value is required.


     char buffer[1024];
     char *bp = buffer;
     size_t remaining = sizeof(buffer);
     int diag;

     diag = snprintf(bp, remaining, "%s", string_to_append_to_buffer);
     if (diag != -1 && diag < remaining) {
        bp += diag, remaining -= diag;
     } else {
        /* Handle overflow/error as necessary */
     }

    ....

The only problem is that the return value for snprintf is 'int', while
the buffer size is size_t; which means on systems with a 64-bit size_t,
the return value isn't large enough to express the correct return value
when the size of the result value exceeds 4GB.   Not generally a problem in
actual code, but something to be aware of.

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


#163495

FromThiago Adams <thiago.adams@gmail.com>
Date2021-11-19 05:38 -0800
Message-ID<210d10fe-b9be-4752-986f-ba08ef8ccd76n@googlegroups.com>
In reply to#163456
On Wednesday, November 17, 2021 at 6:36:09 PM UTC-3, Scott Lurndal wrote:
> David Brown <david...@hesbynett.no> writes: 
> >On 17/11/2021 19:21, Scott Lurndal wrote: 
> >> David Brown <david...@hesbynett.no> writes: 
> >>> On 17/11/2021 16:36, Malcolm McLean wrote: 
> >>>> On Wednesday, 17 November 2021 at 15:34:50 UTC, Scott Lurndal wrote: 
> >>>>> pozz <pozz...@gmail.com> writes: 
> >>>>>> Many times I need to construct a string through a call to sprintf and 
> >>>>>> pass it to an external function. 
> >>>>>> 
> >>>>>> char s[32]; 
> >>>>>> sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year); 
> >>>>>> lcd_write(s); 
> >>>>> One might consider using 'snprintf' instead of 'sprintf'; it is a bit safer. 
> >>>>> 
> >>>> It depends whether wrong results are better or worse than no results. 
> >>>> 
> >>> 
> >>> Generally, a truncated string on the output is better than a stack 
> >>> overflow with your embedded system crashing or going wild. But your 
> >>> needs may vary. 
> >> 
> >> Indeed. Plus a good programmer checks the return value from snprintf. 
> >> Always. 
> >> 
> > 
> >Really? I never do. But I make sure my buffers are the right size for 
> >the job - or that it doesn't matter if there is truncation (such as for 
> >log outputs). I prefer to be sure that my inputs to the function are 
> >correct, than to call the function and check for problems afterwards. 
> >(Different people can have different requirements here - but that's the 
> >way I do it.) 
> >
> I often use snprintf in place of strcat. For that purpose, checking the return 
> value is required. 
> 
> 
> char buffer[1024]; 
> char *bp = buffer; 
> size_t remaining = sizeof(buffer); 
> int diag; 
> 
> diag = snprintf(bp, remaining, "%s", string_to_append_to_buffer); 
> if (diag != -1 && diag < remaining) { 
> bp += diag, remaining -= diag; 
> } else { 
> /* Handle overflow/error as necessary */ 
> } 
> 
> .... 
> 
> The only problem is that the return value for snprintf is 'int', while 
> the buffer size is size_t; which means on systems with a 64-bit size_t, 
> the return value isn't large enough to express the correct return value 
> when the size of the result value exceeds 4GB. Not generally a problem in 
> actual code, but something to be aware of.

And there is a warning when we compare the result of snprintf (int)
against sizeof that returns size_t.

I put cast and this is very annoying.

char buffer[10];
if (snprintf(buffer, sizeof(buffer), "%s", psz) >= (int)sizeof(buffer)) {
   //error
}

Actually sizeof returning size_t requires more casts in other places
of my code. 

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


#163497

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2021-11-19 07:13 -0800
Message-ID<7e0740f6-dfff-479b-b6de-1b0afd908318n@googlegroups.com>
In reply to#163495
On Friday, 19 November 2021 at 13:38:20 UTC, Thiago Adams wrote:
> On Wednesday, November 17, 2021 at 6:36:09 PM UTC-3, Scott Lurndal wrote: 
> > David Brown <david...@hesbynett.no> writes: 
> > >On 17/11/2021 19:21, Scott Lurndal wrote: 
> > >> David Brown <david...@hesbynett.no> writes: 
> > >>> On 17/11/2021 16:36, Malcolm McLean wrote: 
> > >>>> On Wednesday, 17 November 2021 at 15:34:50 UTC, Scott Lurndal wrote: 
> > >>>>> pozz <pozz...@gmail.com> writes: 
> > >>>>>> Many times I need to construct a string through a call to sprintf and 
> > >>>>>> pass it to an external function. 
> > >>>>>> 
> > >>>>>> char s[32]; 
> > >>>>>> sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year); 
> > >>>>>> lcd_write(s); 
> > >>>>> One might consider using 'snprintf' instead of 'sprintf'; it is a bit safer. 
> > >>>>> 
> > >>>> It depends whether wrong results are better or worse than no results. 
> > >>>> 
> > >>> 
> > >>> Generally, a truncated string on the output is better than a stack 
> > >>> overflow with your embedded system crashing or going wild. But your 
> > >>> needs may vary. 
> > >> 
> > >> Indeed. Plus a good programmer checks the return value from snprintf. 
> > >> Always. 
> > >> 
> > > 
> > >Really? I never do. But I make sure my buffers are the right size for 
> > >the job - or that it doesn't matter if there is truncation (such as for 
> > >log outputs). I prefer to be sure that my inputs to the function are 
> > >correct, than to call the function and check for problems afterwards. 
> > >(Different people can have different requirements here - but that's the 
> > >way I do it.) 
> > > 
> > I often use snprintf in place of strcat. For that purpose, checking the return 
> > value is required. 
> > 
> > 
> > char buffer[1024]; 
> > char *bp = buffer; 
> > size_t remaining = sizeof(buffer); 
> > int diag; 
> > 
> > diag = snprintf(bp, remaining, "%s", string_to_append_to_buffer); 
> > if (diag != -1 && diag < remaining) { 
> > bp += diag, remaining -= diag; 
> > } else { 
> > /* Handle overflow/error as necessary */ 
> > } 
> > 
> > .... 
> > 
> > The only problem is that the return value for snprintf is 'int', while 
> > the buffer size is size_t; which means on systems with a 64-bit size_t, 
> > the return value isn't large enough to express the correct return value 
> > when the size of the result value exceeds 4GB. Not generally a problem in 
> > actual code, but something to be aware of.
> And there is a warning when we compare the result of snprintf (int) 
> against sizeof that returns size_t. 
> 
> I put cast and this is very annoying. 
> 
> char buffer[10]; 
> if (snprintf(buffer, sizeof(buffer), "%s", psz) >= (int)sizeof(buffer)) { 
> //error 
> } 
> 
> Actually sizeof returning size_t requires more casts in other places 
> of my code.
>
size_t is a nuisance. The justification for it is that sizes of things in memory
may exceed the range of an int. But it turns into a bulldozer. Every count,
every index variable, as well as sizes of things in bytes, become touched by
size_t.

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


#163460

FromWilliam Ahern <william@25thandClement.com>
Date2021-11-17 20:46 -0800
Message-ID<pd2h6i-dsm1.ln1@wilbur.25thandClement.com>
In reply to#163453
David Brown <david.brown@hesbynett.no> wrote:
> On 17/11/2021 19:21, Scott Lurndal wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>> On 17/11/2021 16:36, Malcolm McLean wrote:
>>>> On Wednesday, 17 November 2021 at 15:34:50 UTC, Scott Lurndal wrote:
>>>>> pozz <pozz...@gmail.com> writes: 
>>>>>> Many times I need to construct a string through a call to sprintf and 
>>>>>> pass it to an external function. 
>>>>>>
>>>>>> char s[32]; 
>>>>>> sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year); 
>>>>>> lcd_write(s);
>>>>> One might consider using 'snprintf' instead of 'sprintf'; it is a bit safer. 
>>>>>
>>>> It depends whether wrong results are better or worse than no results.
>>>>
>>>
>>> Generally, a truncated string on the output is better than a stack
>>> overflow with your embedded system crashing or going wild.  But your
>>> needs may vary.
>> 
>> Indeed.  Plus a good programmer checks the return value from snprintf.
>> Always.
>> 
> 
> Really?  I never do.  But I make sure my buffers are the right size for
> the job - or that it doesn't matter if there is truncation (such as for
> log outputs).  I prefer to be sure that my inputs to the function are
> correct, than to call the function and check for problems afterwards.
> (Different people can have different requirements here - but that's the
> way I do it.)
> 

That is generally the best approach, but doesn't work well with snprintf (or
stringification of data types generally), especially in light of the express
concern about robustness to drive-by edits of the format string.

The way to avoid string buffer errors is to avoid strings and stick to
concrete data types or to process data in a rigorously streaming fashion.
That's true of C and other languages--strings aren't data structures,
they're the antithesis of a data structure. But one nonetheless often finds
themselves dealing with strings either on input or output, unfortunately,
and facing the cruel economic calculus of worse is better. Which I suppose
is why every language spends so much effort chasing a better string type
despite the very phrase, string type, being a contradiction in terms.

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


#163464

FromDavid Brown <david.brown@hesbynett.no>
Date2021-11-18 10:50 +0100
Message-ID<sn57ku$tea$1@dont-email.me>
In reply to#163460
On 18/11/2021 05:46, William Ahern wrote:
> David Brown <david.brown@hesbynett.no> wrote:
>> On 17/11/2021 19:21, Scott Lurndal wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
>>>> On 17/11/2021 16:36, Malcolm McLean wrote:
>>>>> On Wednesday, 17 November 2021 at 15:34:50 UTC, Scott Lurndal wrote:
>>>>>> pozz <pozz...@gmail.com> writes: 
>>>>>>> Many times I need to construct a string through a call to sprintf and 
>>>>>>> pass it to an external function. 
>>>>>>>
>>>>>>> char s[32]; 
>>>>>>> sprintf(s, "Hi %s, today is %d/%d/%d", yourname, day, month, year); 
>>>>>>> lcd_write(s);
>>>>>> One might consider using 'snprintf' instead of 'sprintf'; it is a bit safer. 
>>>>>>
>>>>> It depends whether wrong results are better or worse than no results.
>>>>>
>>>>
>>>> Generally, a truncated string on the output is better than a stack
>>>> overflow with your embedded system crashing or going wild.  But your
>>>> needs may vary.
>>>
>>> Indeed.  Plus a good programmer checks the return value from snprintf.
>>> Always.
>>>
>>
>> Really?  I never do.  But I make sure my buffers are the right size for
>> the job - or that it doesn't matter if there is truncation (such as for
>> log outputs).  I prefer to be sure that my inputs to the function are
>> correct, than to call the function and check for problems afterwards.
>> (Different people can have different requirements here - but that's the
>> way I do it.)
>>
> 
> That is generally the best approach, but doesn't work well with snprintf (or
> stringification of data types generally), especially in light of the express
> concern about robustness to drive-by edits of the format string.
> 

It works perfectly well in the type of programming I do.  Different
kinds of work have different requirements.  In small-systems embedded
programming (which is what I usually work with, and also what the OP is
doing), you know what you are passing to your printf type functions.
You know what the output is connected to (a screen, a UART, a log in
flash, etc.).

But it can be an entirely different matter in other kinds of programming
where you might have the format string coming from an external file of
translations made by a third party, or the endless variety of
complicating factors that can occur on big systems.  Scott could be
right that a good programmer always checks the return value of snprintf
when doing the kind of coding he does - but it is not right for the kind
of coding /I/ do.

> The way to avoid string buffer errors is to avoid strings and stick to
> concrete data types or to process data in a rigorously streaming fashion.

The way to avoid string buffer errors is the same as you avoid any other
errors - good development practices.  That runs the whole gamut from
high level concerns to low-level details.  It includes making sure you
have clear specifications for the code you are writing, making sure the
programmer is appropriately qualified, having code review practices,
testing regimes, automatic checking tools, making sure the data coming
into your code is appropriate, making sure you correctly handle all
cases (including worst cases and pathological cases), and so on.  It's
just like any other coding error.

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


Page 1 of 3  [1] 2 3  Next page →

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


csiph-web