Re: variable length array

Discussion in 'C Programming' started by Dan Pop, Jun 24, 2003.

  1. Dan Pop

    Dan Pop Guest

    In <3ef49249$0$5973$> "Simon Biber" <> writes:

    >"Dan Pop" <> wrote:
    >> -W triggers often undesirable warnings (that's why they
    >> haven't been included in -Wall in the first place)

    >
    >The warnings triggered by -W are often more stylistic things,
    >or reminders that some practise may be a bit dangerous in some
    >situations (even if in the specific case it is actually correct).
    >I quite like those warnings, and prefer to modify my code to work
    >around them rather than disable them, wherever possible.


    I find them a nuisance and see no good reason for working around them.
    The following is a trivial example where the compiler should trust the
    programmer:

    fangorn:~/tmp 336> cat test.c
    #include <string.h>

    void foo(int arg)
    {
    int i;
    for (i = 0; i < strlen("abcde"); i++) /* do something */ ;
    }
    fangorn:~/tmp 337> gcc -c -Wall test.c
    fangorn:~/tmp 338> gcc -c -Wall -W test.c
    test.c: In function `foo':
    test.c:6: warning: comparison between signed and unsigned
    test.c:3: warning: unused parameter `arg'

    I can see NO good reason for doing something with arg to keep -W silent
    and I cannot drop it from the function interface (which is externally
    imposed). Likewise, I don't want to declare i as unsigned for the *sole*
    reason of shutting up -W (or cast the return value of strlen). I only
    use unsigned variables when I have a good reason for that, because of
    reasons discussed in a different thread.

    Dan
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email:
    Dan Pop, Jun 24, 2003
    #1
    1. Advertising

  2. Dan Pop

    Neil Cerutti Guest

    In article <bd9n9g$4j3$>, Dan Pop wrote:
    > In <3ef49249$0$5973$> "Simon
    > Biber" <> writes:
    >>The warnings triggered by -W are often more stylistic things,
    >>or reminders that some practise may be a bit dangerous in some
    >>situations (even if in the specific case it is actually correct).
    >>I quite like those warnings, and prefer to modify my code to work
    >>around them rather than disable them, wherever possible.

    >
    > I find them a nuisance and see no good reason for working around them.
    > The following is a trivial example where the compiler should trust the
    > programmer:
    >
    > fangorn:~/tmp 336> cat test.c
    > #include <string.h>
    >
    > void foo(int arg)
    > {
    > int i;
    > for (i = 0; i < strlen("abcde"); i++) /* do something */ ;
    > }
    > fangorn:~/tmp 337> gcc -c -Wall test.c
    > fangorn:~/tmp 338> gcc -c -Wall -W test.c
    > test.c: In function `foo':
    > test.c:6: warning: comparison between signed and unsigned
    > test.c:3: warning: unused parameter `arg'
    >
    > I can see NO good reason for doing something with arg to keep
    > -W silent and I cannot drop it from the function interface
    > (which is externally imposed).


    It's too bad it's illegal to omit the identifier in such cases.
    Given that, I agree the warning is annoying in this case.

    But an externally imposed function interface that requires
    useless parameters is arguably the real cause of this particular
    annoyance.

    > Likewise, I don't want to declare i as unsigned for the *sole*
    > reason of shutting up -W (or cast the return value of strlen).
    > I only use unsigned variables when I have a good reason for
    > that, because of reasons discussed in a different thread.


    Your strlen usage example is perhaps too academic. The following
    is equivalent, and evinces no such warning:

    void foo(int arg)
    {
    int i;
    for (i = 0; i < 5; i++) /* do something */ ;
    }

    --
    Neil Cerutti
    Neil Cerutti, Jun 24, 2003
    #2
    1. Advertising

  3. Dan Pop

    Zoran Cutura Guest

    Neil Cerutti <> wrote:
    ....
    > Your strlen usage example is perhaps too academic. The following
    > is equivalent, and evinces no such warning:
    >
    > void foo(int arg)
    > {
    > int i;
    > for (i = 0; i < 5; i++) /* do something */ ;
    > }
    >


    I don't see how Dan's example is academic or how yours is less academic.

    sizeof array / sizeof *array

    from my point of view is a somewhat often used term especially in for
    or while loops which yields a unsigned integral value and comparing i
    against it issues the warning Dan showed. I certainly do have a lot of
    such comparisons in my programs and often either cast or declare i as
    unsigned only for that reason.
    --
    Z ()
    "LISP is worth learning for the profound enlightenment experience
    you will have when you finally get it; that experience will make you
    a better programmer for the rest of your days." -- Eric S. Raymond
    Zoran Cutura, Jun 24, 2003
    #3
  4. Neil Cerutti wrote:

    <snip>
    >
    > Here's a slightly less trivial example, that allows me to make my
    > point:
    >
    > void foo(int arg, char *s)
    > {
    > int i; /* wrong */
    > for (i = 0; i < strlen(s); ++i) do_something(s);
    > }
    >
    > Using this example, it becomes possible to say that i ought to be
    > of type size_t, making it's range equal to strlen's range.


    And so it should. But don't you think it's better to move the strlen out of
    the loop?

    --
    Richard Heathfield :
    "Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
    K&R answers, C books, etc: http://users.powernet.co.uk/eton
    Richard Heathfield, Jun 24, 2003
    #4
  5. Dan Pop

    Neil Cerutti Guest

    In article <>, Richard Heathfield wrote:
    > Neil Cerutti wrote:
    >
    ><snip>
    >> Here's a slightly less trivial example, that allows me to make
    >> my point:
    >>
    >> void foo(int arg, char *s)
    >> {
    >> int i; /* wrong */
    >> for (i = 0; i < strlen(s); ++i) do_something(s);
    >> }
    >>
    >> Using this example, it becomes possible to say that i ought to
    >> be of type size_t, making it's range equal to strlen's range.

    >
    > And so it should. But don't you think it's better to move the
    > strlen out of the loop?


    Yes.

    --
    Neil Cerutti
    Neil Cerutti, Jun 24, 2003
    #5
  6. "Richard Heathfield" <> wrote in message
    news:...
    > Neil Cerutti wrote:
    >
    > <snip>
    > >
    > > Here's a slightly less trivial example, that allows me to make my
    > > point:
    > >
    > > void foo(int arg, char *s)
    > > {
    > > int i; /* wrong */
    > > for (i = 0; i < strlen(s); ++i) do_something(s);
    > > }
    > >
    > > Using this example, it becomes possible to say that i ought to be
    > > of type size_t, making it's range equal to strlen's range.

    >
    > And so it should. But don't you think it's better to move the strlen out

    of
    > the loop?


    Actually, it's better to remove strlen completely:

    for( i = 0; s; i++ )
    do_something(s);

    karl m
    karl malbrain, Jun 24, 2003
    #6
  7. Dan Pop

    Zoran Cutura Guest

    Simon Biber <> wrote:
    > "Dan Pop" <> wrote:
    >> "Simon Biber" <> wrote:
    >> > The warnings triggered by -W are often more stylistic things,
    >> > or reminders that some practise may be a bit dangerous in
    >> > some situations (even if in the specific case it is actually
    >> > correct). I quite like those warnings, and prefer to modify
    >> > my code to work around them rather than disable them,
    >> > wherever possible.

    >>
    >> I find them a nuisance and see no good reason for working
    >> around them. The following is a trivial example where the
    >> compiler should trust the programmer:
    >>
    >> fangorn:~/tmp 336> cat test.c
    >> #include <string.h>
    >>
    >> void foo(int arg)
    >> {
    >> int i;
    >> for (i = 0; i < strlen("abcde"); i++) /* do something */ ;
    >> }
    >> fangorn:~/tmp 337> gcc -c -Wall test.c
    >> fangorn:~/tmp 338> gcc -c -Wall -W test.c
    >> test.c: In function `foo':
    >> test.c:6: warning: comparison between signed and unsigned

    >
    > There is very good reason for the warning here as it has
    > uncovered a potential bug in your code. If the value
    > returned by strlen is greater than INT_MAX, your program
    > has undefined behaviour due to overflow.


    I don't see any potential for overflow in the above code.
    As strlen returns a size_t which definitly is a unsigned integer type
    and i is of signed int some conversion will take place. If size_t where
    lower in rank than int (I'm not entirely sure about whether it would be
    allowed to be lower in rank than int) the size_t value would be
    converted to an int due to usual arithmetic conversions if all values of
    size_t could be represented within int. If not, both values would be
    converted to unsigned int and even if i where negativ overflow would not
    occur.

    If size_t is bigger in rank than i will equally be converted to the same
    type and again overlfow can not happen. So I conclude there is no
    potential fro overflow and thereby UB in this code.

    But probably I've missed something.

    --
    Z ()
    "LISP is worth learning for the profound enlightenment experience
    you will have when you finally get it; that experience will make you
    a better programmer for the rest of your days." -- Eric S. Raymond
    Zoran Cutura, Jun 25, 2003
    #7
  8. In article <bdbe4o$s58$-felb.debis.de>,
    Zoran Cutura <> wrote:

    > >> fangorn:~/tmp 336> cat test.c
    > >> #include <string.h>
    > >>
    > >> void foo(int arg)
    > >> {
    > >> int i;
    > >> for (i = 0; i < strlen("abcde"); i++) /* do something */ ;
    > >> }

    > I don't see any potential for overflow in the above code.
    > As strlen returns a size_t which definitly is a unsigned integer type
    > and i is of signed int some conversion will take place. If size_t where
    > lower in rank than int (I'm not entirely sure about whether it would be
    > allowed to be lower in rank than int) the size_t value would be
    > converted to an int due to usual arithmetic conversions if all values of
    > size_t could be represented within int. If not, both values would be
    > converted to unsigned int and even if i where negativ overflow would not
    > occur.
    >
    > If size_t is bigger in rank than i will equally be converted to the same
    > type and again overlfow can not happen. So I conclude there is no
    > potential fro overflow and thereby UB in this code.


    Apart from the fact that strlen ("abcde") is five and no overflow can
    happen, if "abcde" were replaced by a string with 33000 characters and
    int = 16 bit then the i++ will eventually overflow.

    But I suspect the compiler complains about the fact that if i is
    negative (which it can't be in this example) then i is less than strlen
    ("abcde") but (i < strlen ("abcde")) could produce a result of zero.
    Strictly according to the C rules, but wrong.
    Christian Bau, Jun 25, 2003
    #8
  9. Dan Pop

    Simon Biber Guest

    "Zoran Cutura" <> wrote:
    > Simon Biber <> wrote:
    > > "Dan Pop" <> wrote:
    > >> #include <string.h>
    > >>
    > >> void foo(int arg)
    > >> {
    > >> int i;
    > >> for (i = 0; i < strlen("abcde"); i++)
    > >> /* do something */ ;
    > >> }
    > >> fangorn:~/tmp 337> gcc -c -Wall test.c
    > >> fangorn:~/tmp 338> gcc -c -Wall -W test.c
    > >> test.c: In function `foo':
    > >> test.c:6: warning: comparison between signed and unsigned

    > >
    > > There is very good reason for the warning here as it has
    > > uncovered a potential bug in your code. If the value
    > > returned by strlen is greater than INT_MAX, your program
    > > has undefined behaviour due to overflow.

    >
    > I don't see any potential for overflow in the above code.
    >
    > As strlen returns a size_t which definitly is a unsigned
    > integer type and i is of signed int some conversion will
    > take place. If size_t were lower in rank than int (I'm
    > not entirely sure about whether it would be allowed to
    > be lower in rank than int) the size_t value would be
    > converted to an int due to usual arithmetic conversions
    > if all values of size_t could be represented within int.
    > If not, both values would be converted to unsigned int
    > and even if i where negativ overflow would not occur. If
    > size_t is bigger in rank than i will equally be converted
    > to the same type and again overlfow can not happen. So I
    > conclude there is no potential fro overflow and thereby
    > UB in this code.


    The overflow is not in the conversion. In fact, conversions
    of values outside the range of the target type are never
    considered as `overflow'. The semantics are quite different.

    (1) In the case of converting to an unsigned integer type,
    the results are strictly defined to wrap around, as if
    the maximum value plus one was added or subtracted
    until within the range.

    (2) In the case of converting to a signed integer type, the
    resulting value is implementation defined, or (in C99)
    an implementation-defined signal may be raised. However,
    there is not an outright undefined behaviour.

    (3) When the result of an unsigned arithmetic operation
    doesn't fit within the range, unsigned types never
    overflow -- they wrap around.

    (4) On the other hand, when computing an arithmetic overflow
    in a signed type there is immediate undefined behaviour.
    The standard doesn't specify an implementation-defined
    result or signal.

    In practise, of course, many 2's complement implementations
    behave exactly the same for all four cases, which leads to
    confusion.

    > But probably I've missed something.


    If the value returned by strlen is greater than INT_MAX,
    the comparison will always be true. Then after some time
    while incrementing through the loop, i will equal INT_MAX,
    it will be incremented once more, and overflow will occur.
    This is arithmetic overflow in a signed type, not a
    conversion, and so it is undefined behaviour.

    --
    Simon.
    Simon Biber, Jun 25, 2003
    #9
  10. Dan Pop

    Richard Bos Guest

    Richard Heathfield <> wrote:

    > Neil Cerutti wrote:
    >
    > <snip>
    > >
    > > Here's a slightly less trivial example, that allows me to make my
    > > point:
    > >
    > > void foo(int arg, char *s)
    > > {
    > > int i; /* wrong */
    > > for (i = 0; i < strlen(s); ++i) do_something(s);
    > > }
    > >
    > > Using this example, it becomes possible to say that i ought to be
    > > of type size_t, making it's range equal to strlen's range.

    >
    > And so it should. But don't you think it's better to move the strlen out of
    > the loop?


    No. If do_something() can set s to '\0', the loop will abort next
    time, and this effect may have been intentional. If do_something() never
    changes s, or rather, never sets it to the null character, the
    compiler can figure that out and optimise the strlen() call away itself.
    And leaving the strlen() where it is makes for a semantically better
    (read: more naturally expressed) program.

    Richard
    Richard Bos, Jun 25, 2003
    #10
  11. Dan Pop

    Zoran Cutura Guest

    Simon Biber <> wrote:
    > "Zoran Cutura" <> wrote:
    >> Simon Biber <> wrote:

    >
    >> But probably I've missed something.

    >
    > If the value returned by strlen is greater than INT_MAX,
    > the comparison will always be true. Then after some time
    > while incrementing through the loop, i will equal INT_MAX,
    > it will be incremented once more, and overflow will occur.
    > This is arithmetic overflow in a signed type, not a
    > conversion, and so it is undefined behaviour.


    Ahh, I see it's not in the comparison but in the increment.

    >


    --
    Z ()
    "LISP is worth learning for the profound enlightenment experience
    you will have when you finally get it; that experience will make you
    a better programmer for the rest of your days." -- Eric S. Raymond
    Zoran Cutura, Jun 25, 2003
    #11
  12. Dan Pop

    Dan Pop Guest

    In <3ef92f55$0$8262$> "Simon Biber" <> writes:

    >"Dan Pop" <> wrote:
    >> "Simon Biber" <> wrote:
    >> > The warnings triggered by -W are often more stylistic things,
    >> > or reminders that some practise may be a bit dangerous in
    >> > some situations (even if in the specific case it is actually
    >> > correct). I quite like those warnings, and prefer to modify
    >> > my code to work around them rather than disable them,
    >> > wherever possible.

    >>
    >> I find them a nuisance and see no good reason for working
    >> around them. The following is a trivial example where the
    >> compiler should trust the programmer:
    >>
    >> fangorn:~/tmp 336> cat test.c
    >> #include <string.h>
    >>
    >> void foo(int arg)
    >> {
    >> int i;
    >> for (i = 0; i < strlen("abcde"); i++) /* do something */ ;
    >> }
    >> fangorn:~/tmp 337> gcc -c -Wall test.c
    >> fangorn:~/tmp 338> gcc -c -Wall -W test.c
    >> test.c: In function `foo':
    >> test.c:6: warning: comparison between signed and unsigned

    >
    >There is very good reason for the warning here as it has
    >uncovered a potential bug in your code. If the value
    >returned by strlen is greater than INT_MAX, your program
    >has undefined behaviour due to overflow.


    Since when is allowed INT_MAX to be less than 5? I may have more
    information than the compiler, therefore the compiler must trust me.

    >You should always use size_t for loop iterators whose bound
    >is expressed in size_t. This includes arrays when you use
    > sizeof foo / sizeof *foo
    >as the bound.


    Sheer bullshit! If I *know* that int is enough, there's NO reason for
    using size_t.

    >> test.c:3: warning: unused parameter `arg'
    >>
    >> I can see NO good reason for doing something with arg to keep
    >> -W silent and I cannot drop it from the function interface
    >> (which is externally imposed).

    >
    >In my experience externally imposed interfaces are uncommon,


    Have a look at the specification of signal() sometime.

    >and I see the odd cast to void as useful self-documentation.
    >It lets the reader of the code immediately see that you
    >intentially do not use the value of the argument.


    Or he might start wondering why I am doing such a silly thing as casting
    an otherwise unused argument to void.

    If I don't use the value of the argument (as is usually the case with
    my signal handlers), what is the obvious conclusion?

    >> Likewise, I don't want to declare i as unsigned for the
    >> *sole* reason of shutting up -W (or cast the return value
    >> of strlen). I only use unsigned variables when I have a
    >> good reason for that, because of reasons discussed in a
    >> different thread.

    >
    >But there is a very good reason to use a size_t variable here!


    Nope! Single letter variables are often reused as loop counters and
    temporary variables. More often than not, the type int is more
    appropriate than an unsigned type and the decision should be mine, not
    compiler's, anyway.

    >So, I would write:
    > #include <string.h>
    >
    > void foo(int arg)
    > {
    > (void)arg;
    > for (size_t i = 0, n = strlen("abcde"); i < n; i++)
    > {
    > /* do something */
    > }
    > }
    >for which `gcc -c -std=c99 -pedantic -Wall -W -O2 warn.c`
    >gives no warnings.


    That's precisely my point: why bother with options that *force* you to
    code around them? What guarantee do you have that *another* compiler
    won't complain about the useless statement (void)arg; ?

    Apart from that, your code is not portable to *most* C compilers, for no
    *good* reason at all.

    Dan
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email:
    Dan Pop, Jun 25, 2003
    #12
  13. Dan Pop

    Jirka Klaue Guest

    Richard Bos wrote:
    > Richard Heathfield <> wrote:
    >>Neil Cerutti wrote:

    ....
    >>>Here's a slightly less trivial example, that allows me to make my
    >>>point:
    >>>
    >>>void foo(int arg, char *s)
    >>>{
    >>> int i; /* wrong */
    >>> for (i = 0; i < strlen(s); ++i) do_something(s);
    >>>}
    >>>
    >>>Using this example, it becomes possible to say that i ought to be
    >>>of type size_t, making it's range equal to strlen's range.

    >>
    >>And so it should. But don't you think it's better to move the strlen out of
    >>the loop?

    >
    > No. If do_something() can set s to '\0', [...]


    It's not possible, if do_something is a function. And if do_something
    is a macro, it does not have proper notation.

    Jirka
    Jirka Klaue, Jun 25, 2003
    #13
  14. Dan Pop

    Simon Biber Guest

    "Dan Pop" <> wrote:
    > "Simon Biber" <> writes:
    > > There is very good reason for the warning here as it
    > > has uncovered a potential bug in your code. If the
    > > value returned by strlen is greater than INT_MAX,
    > > your program has undefined behaviour due to overflow.

    >
    > Since when is allowed INT_MAX to be less than 5? I may
    > have more information than the compiler, therefore the
    > compiler must trust me.


    I said "potential bug". There is no bug in your code,
    but in most cases when looping through a string there
    is the possibility of it being of any length, and it
    is quite possible it could exceed INT_MAX.

    You clearly like to write code that gets the job done but
    leaves no room for expansion or re-use. I prefer to code
    in the most robust way available.

    > >You should always use size_t for loop iterators whose
    > >bound is expressed in size_t. This includes arrays
    > >when you use
    > > sizeof foo / sizeof *foo
    > >as the bound.

    >
    > Sheer bullshit! If I *know* that int is enough, there's
    > NO reason for using size_t.


    Again, you know that int is enough now, but who knows what
    changes you or other people may wish to make to your code
    in the future? It is better to do things properly now so
    that future expansion will be painless.

    > >In my experience externally imposed interfaces are uncommon,

    >
    > Have a look at the specification of signal() sometime.


    Name some common, portable, standard-conforming uses of signal().

    > >and I see the odd cast to void as useful self-documentation.
    > >It lets the reader of the code immediately see that you
    > >intentially do not use the value of the argument.

    >
    > Or he might start wondering why I am doing such a silly thing
    > as casting an otherwise unused argument to void.


    The cast to void is a fairly well-known signal for "I don't
    care what value this expression has".

    > If I don't use the value of the argument (as is usually the
    > case with my signal handlers), what is the obvious conclusion?


    If the function is long and/or complicated it may not be obvious
    at a glance whether or not each argument is actually used.
    Furthermore the non-use of an argument is so often a mistake that
    a reader is forced to reevaluate whether or not you really did
    mean to not use it the argument.

    > > But there is a very good reason to use a size_t
    > > variable here!

    >
    > Nope! Single letter variables are often reused as loop
    > counters and temporary variables. More often than not,
    > the type int is more appropriate than an unsigned type
    > and the decision should be mine, not compiler's, anyway.


    Variables should be reduced to the minimum scope necessary.
    Single letter variables should not be reused, this creates
    confusion over whether their value is significant between
    uses.

    I like the for(type i=0; i<n; i++) form from C99, where the
    variable goes out of scope immediately on exit from the loop.

    > >So, I would write:
    > > #include <string.h>
    > >
    > > void foo(int arg)
    > > {
    > > (void)arg;
    > > for (size_t i = 0, n = strlen("abcde"); i < n; i++)
    > > {
    > > /* do something */
    > > }
    > > }
    > >for which `gcc -c -std=c99 -pedantic -Wall -W -O2 warn.c`
    > >gives no warnings.

    >
    > That's precisely my point: why bother with options that
    > *force* you to code around them?


    I don't feel forced to code around it! I believe it is good
    style to code in such a way that the warnings don't come up.

    > What guarantee do you have that *another* compiler
    > won't complain about the useless statement (void)arg; ?


    None; a compiler is allowed to complain about anything.
    However, in my experience compilers universally take a
    cast as a sign to shut up.

    > Apart from that, your code is not portable to *most* C
    > compilers, for no *good* reason at all.


    Bogus. My code is portable to *all* C compilers.

    Most of the compilers that used to be C compilers,
    are now obsolete. C99 replaced C89. C89 is not C.

    Come to think of it, since I started programming in C
    after C99 was released, I've never used a C compiler!

    :)

    --
    Simon.
    Simon Biber, Jun 25, 2003
    #14
  15. Dan Pop

    Jirka Klaue Guest

    Simon Biber wrote:
    [...]
    > None; a compiler is allowed to complain about anything.
    > However, in my experience compilers universally take a
    > cast as a sign to shut up.


    Intel's C compiler does not, so "universally" is too strong.

    int i = 42;
    char *p = (char *)i;

    main.c(155): remark #171: invalid type conversion: "int" to "char *"
    char *p = (char *)i;
    ^

    Jirka
    Jirka Klaue, Jun 25, 2003
    #15
  16. Dan Pop

    Daniel Haude Guest

    On Wed, 25 Jun 2003 08:01:43 GMT,
    Richard Bos <> wrote
    in Msg. <>

    > No. If do_something() can set s to '\0', the loop will abort next
    > time, and this effect may have been intentional. If do_something() never
    > changes s, or rather, never sets it to the null character, the
    > compiler can figure that out and optimise the strlen() call away itself.


    Not knowing much about modern optimizing compilers, and also not wanting
    to drag this thread off-topic, but just out of curiosity: How far do
    compilers go when looking at such code? Do the optimizations cross
    function calls?

    > And leaving the strlen() where it is makes for a semantically better
    > (read: more naturally expressed) program.


    True. But in my mind, strlen() is still nothing but a dumb loop that
    counts all non-zero characters from the beginning of a string each time it
    is called, so buffering strlen()'s result in some local variable whenever
    I want to use a (constant-length) string's length more than once is a
    habit of mine that looks pretty unbreakable.

    --Daniel

    --
    "With me is nothing wrong! And with you?" (from r.a.m.p)
    Daniel Haude, Jun 25, 2003
    #16
  17. Dan Pop

    Daniel Haude Guest

    On 25 Jun 2003 11:19:54 GMT,
    Dan Pop <> wrote
    in Msg. <bdc0gq$eoc$>

    > Or he might start wondering why I am doing such a silly thing as casting
    > an otherwise unused argument to void.
    >
    > If I don't use the value of the argument (as is usually the case with
    > my signal handlers), what is the obvious conclusion?


    That you don't need it. But if you like to compile with all warnings set
    to full blast (like I do), it is all too easy to miss the one important
    diagnostic in a screenful of "unused argument" warnings. I once wasted
    half an afternoon looking for a bug which was indeed caused by an unused
    argument, and I only found it by (void)ing the intentionally unused
    arguments in two dozen signal handlers.

    >>for which `gcc -c -std=c99 -pedantic -Wall -W -O2 warn.c`
    >>gives no warnings.

    >
    > That's precisely my point: why bother with options that *force* you to
    > code around them?


    Reason given above.

    > What guarantee do you have that *another* compiler
    > won't complain about the useless statement (void)arg; ?


    None. If I wanted to code in such a way that all compilers happily ate my
    code without spitting out warnings, I'd probably have to define a macro
    THROWAWAY(arg) which expands to different things for different compilers.

    --Daniel

    --
    "With me is nothing wrong! And with you?" (from r.a.m.p)
    Daniel Haude, Jun 25, 2003
    #17
  18. Dan Pop

    Richard Bos Guest

    Jirka Klaue <-berlin.de> wrote:

    > Richard Bos wrote:
    > > Richard Heathfield <> wrote:
    > >>And so it should. But don't you think it's better to move the strlen out of
    > >>the loop?

    > >
    > > No. If do_something() can set s to '\0', [...]

    >
    > It's not possible, if do_something is a function. And if do_something
    > is a macro, it does not have proper notation.


    True. But people _do_ use all-lower-caps macros. All the more reason to
    leave the strlen() in and trust the optimiser, just to spite that kind
    of person <g>.

    Ricahrd
    Richard Bos, Jun 25, 2003
    #18
  19. Dan Pop

    Richard Bos Guest

    Daniel Haude <-hamburg.de> wrote:

    > Richard Bos <> wrote
    >
    > > And leaving the strlen() where it is makes for a semantically better
    > > (read: more naturally expressed) program.

    >
    > True. But in my mind, strlen() is still nothing but a dumb loop that
    > counts all non-zero characters from the beginning of a string each time it
    > is called,


    Ah. And this is where you're wrong. strlen() is a function that return
    the length of the string. That it is entirely likely that it does this
    by counting characters should not prevent you from thinking on a higher
    level. After all, _you're_ not a microprocessor.

    Richard
    Richard Bos, Jun 25, 2003
    #19
  20. Dan Pop

    Dan Pop Guest

    In <3ef99341$0$8262$> "Simon Biber" <> writes:

    >"Dan Pop" <> wrote:
    >> "Simon Biber" <> writes:
    >> > There is very good reason for the warning here as it
    >> > has uncovered a potential bug in your code. If the
    >> > value returned by strlen is greater than INT_MAX,
    >> > your program has undefined behaviour due to overflow.

    >>
    >> Since when is allowed INT_MAX to be less than 5? I may
    >> have more information than the compiler, therefore the
    >> compiler must trust me.

    >
    >I said "potential bug". There is no bug in your code,
    >but in most cases when looping through a string there
    >is the possibility of it being of any length, and it
    >is quite possible it could exceed INT_MAX.


    But the point is that I have additional information that rules out this
    *theoretical* possibility. Therefore, there is no good reason for using
    size_t.

    Apart from that, when was the last time you used a string whose size
    exceeded INT_MAX, so that the "quite possible" in your assertion is
    justified?

    >You clearly like to write code that gets the job done but
    >leaves no room for expansion or re-use. I prefer to code
    >in the most robust way available.


    Bullshit. I've never had any problem reusing or expanding my code.
    If I decide, at design time, that the right type for a variable is int,
    then I know what I'm doing. The compiler has no business to question my
    decision.

    >> >You should always use size_t for loop iterators whose
    >> >bound is expressed in size_t. This includes arrays
    >> >when you use
    >> > sizeof foo / sizeof *foo
    >> >as the bound.

    >>
    >> Sheer bullshit! If I *know* that int is enough, there's
    >> NO reason for using size_t.

    >
    >Again, you know that int is enough now, but who knows what
    >changes you or other people may wish to make to your code
    >in the future? It is better to do things properly now so
    >that future expansion will be painless.


    You're missing the point! Unsigned variables have plenty of pitfalls
    and one of them could affect the future changes (especially if they are
    done by someone with less experience). By choosing the type int, where
    it is the *right* type, I'm ensuring that even a non-experienced
    programmer can maintain the code. If you still can't see my point,
    replace strlen(something) by sizeof(double) in my original example.
    In theory, sizeof(double) could exceed 32767, yet I'm perfectly willing
    to ignore this possibility.

    >> >In my experience externally imposed interfaces are uncommon,

    >>
    >> Have a look at the specification of signal() sometime.

    >
    >Name some common, portable, standard-conforming uses of signal().


    #include <signal.h>

    volatile sig_atomic_t interrupt;

    void handler(int signo)
    {
    interrupt = 1;
    }
    ....
    signal(SIGINT, handler);
    signal(SIGTERM, handler);

    >> >and I see the odd cast to void as useful self-documentation.
    >> >It lets the reader of the code immediately see that you
    >> >intentially do not use the value of the argument.

    >>
    >> Or he might start wondering why I am doing such a silly thing
    >> as casting an otherwise unused argument to void.

    >
    >The cast to void is a fairly well-known signal for "I don't
    >care what value this expression has".


    Chapter and verse, please. Or other source for this widespread knowledge.

    >> If I don't use the value of the argument (as is usually the
    >> case with my signal handlers), what is the obvious conclusion?

    >
    >If the function is long and/or complicated it may not be obvious
    >at a glance whether or not each argument is actually used.


    Why should anyone care?

    >Furthermore the non-use of an argument is so often a mistake that

    ^^^^^^^^
    >a reader is forced to reevaluate whether or not you really did
    >mean to not use it the argument.


    Care to produce some supporting data for "so often"? I've never ignored
    an argument by mistake, each and every time it was a deliberate decision.

    >> > But there is a very good reason to use a size_t
    >> > variable here!

    >>
    >> Nope! Single letter variables are often reused as loop
    >> counters and temporary variables. More often than not,
    >> the type int is more appropriate than an unsigned type
    >> and the decision should be mine, not compiler's, anyway.

    >
    >Variables should be reduced to the minimum scope necessary.


    That would mean opening plenty of blocks for no good reason. IIRC, it
    was E.R. Tisdale advocating this approach.

    >Single letter variables should not be reused, this creates
    >confusion over whether their value is significant between
    >uses.


    No such confusion is possible, when the reuse starts be assigning a new
    value. It would be downright idiotic to use a different loop control
    variable for each independent loop in a function.

    >I like the for(type i=0; i<n; i++) form from C99, where the
    >variable goes out of scope immediately on exit from the loop.


    It's non-portable. Some people do care about portability, even if you
    don't.

    >> >So, I would write:
    >> > #include <string.h>
    >> >
    >> > void foo(int arg)
    >> > {
    >> > (void)arg;
    >> > for (size_t i = 0, n = strlen("abcde"); i < n; i++)
    >> > {
    >> > /* do something */
    >> > }
    >> > }
    >> >for which `gcc -c -std=c99 -pedantic -Wall -W -O2 warn.c`
    >> >gives no warnings.

    >>
    >> That's precisely my point: why bother with options that
    >> *force* you to code around them?

    >
    >I don't feel forced to code around it! I believe it is good
    >style to code in such a way that the warnings don't come up.


    I don't. While the unused argument issue is harmless, the gratuitous
    usage of unsigned variables is NOT.

    >> What guarantee do you have that *another* compiler
    >> won't complain about the useless statement (void)arg; ?

    >
    >None; a compiler is allowed to complain about anything.
    >However, in my experience compilers universally take a
    >cast as a sign to shut up.


    Is it "your experience" or "universally"?

    >> Apart from that, your code is not portable to *most* C
    >> compilers, for no *good* reason at all.

    >
    >Bogus. My code is portable to *all* C compilers.


    By a bogus definition of C. Your code is non-portable to most of
    the real world C compilers, period.

    >Most of the compilers that used to be C compilers,
    >are now obsolete. C99 replaced C89. C89 is not C.


    You're severely confused. One ISO standard replaced another. Up to now,
    this had no significant impact either on the industry or on the academia.
    The C programming community at large is ignoring the C99 specification.

    Furthermore, as attested by comp.std.c, copies of the ISO C90 standard
    are still in constant demand (and at least one national standardisation
    organisation, BSI, is currently selling them).

    The value of an ISO standard is determined by its impact on the industry
    that's supposed to use it. Until now, C99 had practically none.

    Dan
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email:
    Dan Pop, Jun 25, 2003
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mitchua
    Replies:
    5
    Views:
    2,715
    Eric J. Roode
    Jul 17, 2003
  2. =?Utf-8?B?SG96aQ==?=
    Replies:
    1
    Views:
    6,937
    Ken Cox [Microsoft MVP]
    Jun 2, 2004
  3. Adam Warner

    Flexible array member + variable length array

    Adam Warner, Feb 3, 2005, in forum: C Programming
    Replies:
    10
    Views:
    785
    S.Tobias
    Feb 10, 2005
  4. Tom
    Replies:
    3
    Views:
    199
    salsablr
    Dec 20, 2004
  5. Tuan  Bui
    Replies:
    14
    Views:
    464
    it_says_BALLS_on_your forehead
    Jul 29, 2005
Loading...

Share This Page