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)

Reply via email to