On 2016-09-06 10:44:12 -0500, Derek Martin wrote:
> On Tue, Sep 06, 2016 at 01:10:36PM +0200, Vincent Lefevre wrote:
> > On 2016-09-05 19:07:18 -0500, Derek Martin wrote:
> > > On Mon, Sep 05, 2016 at 10:32:40AM -0500, Derek Martin wrote:
> > > > Is strfcpy() widely available?
> > >
> > > Ah, now I see that strfcpy() is a Mutt-specific macro that intends to
> > > make strncpy() safer. I was actually thinking of strlcpy(), which is
> > > equivalent to Mutt's strfcpy(); but it does not matter. ALL of these
> > > functions suffer from the same affliction: If dest is too small, they
> > > all silently lose data on copy.
> >
> > The strfcpy macro looks awful:
>
> Firstly, I'll note that, given the existing macros don't seem to have
> caused anyone any grief, the exact macro syntax is largely an academic
> consideration. =8^)
Not really. Code gets modified. So, bugs may appear in the future.
This happened in MPFR: my new code wasn't working and I was wondering
why... until I found that someone who wrote macros forgot parentheses.
> But I like those discussions, so I'll blather on a bit about it:
>
> > # define strfcpy(A,B,C) strncpy(A,B,C), *(A+(C)-1)=0
>
> Ah, that's not the definition I saw, but it turns out it's defined in
> several places, with two different definitions.
I took the only one that was in a .h file (lib.h) and thought that
it was used globally. Again, such duplication makes code hard to
maintain.
> The other one is in rfc822.c:
>
> rfc822.c:#define strfcpy(a,b,c) {if (c) {strncpy(a,b,c);a[c-1]=0;}}
There's also one in dotlock.c, but the same as the one in lib.h.
> Note the block syntax, similar to what I used. At least on GCC, this
> does not cause compilation problems in the vast majority of cases,
> including the one you highlighted,
The example I gave was invalid C code with the above macro, and it
becomes valid if do ... while(0) is used. Here's a simple example:
#define foo(x) { return x; }
int main (void)
{
if (1)
foo(0);
else
return 1;
}
zira:~> gcc t.c
t.c: In function ‘main’:
t.c:7:3: error: ‘else’ without a previous ‘if’
else
^~~~
See
http://stackoverflow.com/questions/154136/why-use-apparently-meaningless-do-while-and-if-else-statements-in-c-c-macros
This is even documented in GCC's cpp manual:
https://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html
More on: https://www.google.com/search?q=do+while+0+c+macro
> though I can't say how other
> compilers might treat it, or guess what cases I might be missing...
> For instance, with gcc the following program (which is basically an
> expansion of the macro syntax I suggested) compiles and runs fine,
> even with -Wall -Werror:
>
>
> -=-=-=-=-=-=-=-=-
> $ cat blah.c
> #include <stdio.h>
>
> int main(int argc, char **argv)
> {
> if (argc > 0){
> { printf("argc is %d\n", argc); };
> } else {
> { printf("argc is not greater than zero\n"); };
> }
> return 0;
> }
This is because you use two levels of curly brackets. Said otherwise,
with my example, you won't have problems with:
#define foo(x) { return x; }
int main (void)
{
if (1)
{ foo(0); }
else
{ return 1; }
}
But look at the Mutt code: most often, additional curly brackets
are not used when not needed a priori.
--
Vincent Lefèvre <[email protected]> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)