Watcom vs. gcc/icl/cl difference

Discussion in 'C Programming' started by pemo, Oct 7, 2005.

  1. pemo

    pemo Guest

    I've just been trying out the Watcom compiler from
    http://www.openwatcom.org, and almost immediately compiled some working
    source that errored.

    The code is

    char buffer[1000];

    ...

    if(opt & out_std)
    {
    fputs(&buffer, stdout);
    }

    Note that &buffer should [ideally] have been either &buffer[0] or just plain
    buffer.

    However, the same code compiles cleanly using gcc (ecven when
    using -pedantic), icl, and MS's cl compilers.

    In the c99 std it has the following:
    6.5.3.2 Address and indirection operators

    Constraints

    1 The operand of the unary & operator shall be either a function designator,
    the result of a

    [] or unary * operator, or an lvalue that designates an object that is not a
    bit-field and is

    not declared with the register storage-class specifier.

    I'm interpreting the beginning of this as saying that the follow are valid:

    char array[1];

    int n;

    int * p;

    &array[0];

    &n;

    &*p;

    However, I can't find anything that says that [say] puts(&buffer) is valid.

    So, any comments?
     
    pemo, Oct 7, 2005
    #1
    1. Advertising

  2. "pemo" <> wrote in message
    news:di6akb$a5p$...
    > I've just been trying out the Watcom compiler from
    > http://www.openwatcom.org, and almost immediately compiled some working
    > source that errored.
    >
    > The code is
    >
    > char buffer[1000];
    >
    > ...
    >
    > if(opt & out_std)
    > {
    > fputs(&buffer, stdout);
    > }
    >
    > Note that &buffer should [ideally] have been either &buffer[0] or just

    plain
    > buffer.


    fputs() takes pointer to a char, not pointer to a buffer, hence either
    buffer
    or
    &buffer[0]
    is what you must pass to fputs().

    &buffer has a different type, a pointer to a buffer of 1000 chars,
    (*)[1000].

    Correct example:
    {
    char b[100];
    char (*p1)[100] = &b;
    char* p2 = b;
    }


    Incorrect example:
    {
    char b[100];
    char (*p1)[100] = b;
    char* p2 = &b;
    }

    Alex
     
    Alexei A. Frounze, Oct 7, 2005
    #2
    1. Advertising

  3. pemo

    Skarmander Guest

    pemo wrote:
    > I've just been trying out the Watcom compiler from
    > http://www.openwatcom.org, and almost immediately compiled some working
    > source that errored.
    >
    > The code is
    >
    > char buffer[1000];
    >
    > ...
    >
    > if(opt & out_std)
    > {
    > fputs(&buffer, stdout);
    > }
    >
    > Note that &buffer should [ideally] have been either &buffer[0] or just plain
    > buffer.
    >
    > However, the same code compiles cleanly using gcc (ecven when
    > using -pedantic), icl, and MS's cl compilers.

    <snip>

    gcc --version

    gcc (GCC) 3.4.2 (mingw-special)
    Copyright (C) 2004 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions. There is
    NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
    PURPOSE.

    foo.c:
    #include <stdio.h>

    void foo() {
    char buffer[1000];

    fputs(&buffer, stdout);
    }

    gcc -c test.c

    foo.c: In function `foo':
    foo.c:6: warning: passing arg 1 of `fputs' from incompatible pointer type

    What version of gcc are you using? This isn't what I call "compiling
    cleanly".

    S.
     
    Skarmander, Oct 7, 2005
    #3
  4. pemo

    Skarmander Guest

    Skarmander wrote:
    <snip>
    > gcc -c test.c
    >
    > foo.c: In function `foo':


    Heh. I know I should have attached a screendump!

    S.
     
    Skarmander, Oct 7, 2005
    #4
  5. pemo

    Eric Sosman Guest

    pemo wrote On 10/07/05 13:18,:
    > I've just been trying out the Watcom compiler from
    > http://www.openwatcom.org, and almost immediately compiled some working
    > source that errored.
    >
    > The code is
    >
    > char buffer[1000];
    >
    > ...
    >
    > if(opt & out_std)
    > {
    > fputs(&buffer, stdout);
    > }
    >
    > Note that &buffer should [ideally] have been either &buffer[0] or just plain
    > buffer.
    >
    > However, the same code compiles cleanly using gcc (ecven when
    > using -pedantic), icl, and MS's cl compilers.


    If a correct prototype for fputs() is in scope, a
    diagnostic is required. Since the code uses `stdout'
    as an identifier, it is 99.44% likely that <stdio.h>
    has been included (and 0.56% likely that the code is
    utterly, hopelessly bogus). If <stdio.h> was included,
    a correct prototype for fputs() should be in scope.
    Therefore, it is 99.44% likely that all the compilers
    (or the headers) are broken.

    ... or is it just faintly possible that the code you
    show isn't the code you fed to the compilers? Since what
    you've shown won't compile on any C compiler I have access
    to or have ever heard of, we cannot rule out that faint
    possibility, can we? Would you consider posting *real*
    code instead of a half-baked hacked-up paraphrase?

    --
     
    Eric Sosman, Oct 7, 2005
    #5
  6. pemo

    pemo Guest

    > gcc (GCC) 3.4.2 (mingw-special)
    > Copyright (C) 2004 Free Software Foundation, Inc.
    > This is free software; see the source for copying conditions. There is NO
    > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
    > PURPOSE.
    >
    > foo.c:
    > #include <stdio.h>
    >
    > void foo() {
    > char buffer[1000];
    >
    > fputs(&buffer, stdout);
    > }
    >
    > gcc -c test.c
    >
    > foo.c: In function `foo':
    > foo.c:6: warning: passing arg 1 of `fputs' from incompatible pointer type
    >
    > What version of gcc are you using? This isn't what I call "compiling
    > cleanly".


    Interesting! I'm using Dev-C++ and, according to a gcc -v in \dev-cpp\bin
    it's also 3.4.2.

    Ahhhhh - very red faced!

    In an attempt to show a clean example, I [um] edited out a cast!

    fputs((const char *)&buffer, echoFP);

    Ok lesson learned - like I can now see why that wasn't such a great idea!

    However - I say to myself "well, in that case, that line of code was surely
    never executed!". So, I took out the newly inserted [0], and put it back to
    its original and inserted an extra puts():

    puts("yup");
    fputs((const char *)&buffer, echoFP);

    The code runs fine.

    Here's the whole function [probably going to regret this; although it's not
    my code!] - used as a kind of printf/fprint etc.


    /* Used to output stuff to the console and, optionally, to a file.
    */
    static void out(int opt, const char * format, ...)
    {
    /* Potential for buffer overrun here: but *unlikely*. Maybe work a
    decent malloc in here in the future though!
    */
    auto char buffer[1000];

    auto va_list ap;

    va_start(ap, format);


    /* Output to buffer according to what's passed in format and ap (no
    matter what).
    */
    vsprintf(&buffer[0], format, ap);

    /* stdout output.
    */
    if(opt & out_std)
    {
    puts("here");
    fputs((const char *)&buffer, stdout);
    }

    /* File output if fp points to something.
    */
    if(opt & out_fle)
    {
    if(echoFP != NULL)
    {
    fputs(&buffer[0], echoFP);
    fflush(echoFP);
    }
    else
    {
    out(out_err, "function 'out' called with out_fle, but file
    pointer is invalid!");
    }
    }

    /* stderr output.
    */
    if(opt & out_err)
    {
    fputs((const char *)&buffer[0], stderr);
    }

    /* Invalid flags given? This is not a totally exhaustive test as
    opt_??? are
    static const int out_std = 1;
    static const int out_err = 2;
    static const int out_fle = 4;
    static const int out_reg = out_std | out_fle;
    static const int opt_all = out_err | out_std | out_fle;
    */
    if(opt < 1 || opt > opt_all)
    {
    /* Better report this!
    */
    out(out_err, "function 'out' called using opt of %d: which is
    invalid", opt);
    }

    fflush(stdout);
    fflush(stderr);

    va_end(ap);
    }
     
    pemo, Oct 7, 2005
    #6
  7. pemo

    pemo Guest

    "Eric Sosman" <> wrote in message
    news:di6crf$nth$...
    >
    >
    > pemo wrote On 10/07/05 13:18,:
    >> I've just been trying out the Watcom compiler from
    >> http://www.openwatcom.org, and almost immediately compiled some working
    >> source that errored.
    >>
    >> The code is
    >>
    >> char buffer[1000];
    >>
    >> ...
    >>
    >> if(opt & out_std)
    >> {
    >> fputs(&buffer, stdout);
    >> }
    >>
    >> Note that &buffer should [ideally] have been either &buffer[0] or just
    >> plain
    >> buffer.
    >>
    >> However, the same code compiles cleanly using gcc (ecven when
    >> using -pedantic), icl, and MS's cl compilers.

    >
    > If a correct prototype for fputs() is in scope, a
    > diagnostic is required. Since the code uses `stdout'
    > as an identifier, it is 99.44% likely that <stdio.h>
    > has been included (and 0.56% likely that the code is
    > utterly, hopelessly bogus). If <stdio.h> was included,
    > a correct prototype for fputs() should be in scope.
    > Therefore, it is 99.44% likely that all the compilers
    > (or the headers) are broken.
    >
    > ... or is it just faintly possible that the code you
    > show isn't the code you fed to the compilers? Since what
    > you've shown won't compile on any C compiler I have access
    > to or have ever heard of, we cannot rule out that faint
    > possibility, can we? Would you consider posting *real*
    > code instead of a half-baked hacked-up paraphrase?


    stdio in scope -

    > Would you consider posting *real*
    > code instead


    full function code shown in other post
     
    pemo, Oct 7, 2005
    #7
  8. pemo

    Skarmander Guest

    pemo wrote:
    >>gcc (GCC) 3.4.2 (mingw-special)
    >>Copyright (C) 2004 Free Software Foundation, Inc.
    >>This is free software; see the source for copying conditions. There is NO
    >>warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
    >>PURPOSE.
    >>
    >>foo.c:
    >>#include <stdio.h>
    >>
    >>void foo() {
    >>char buffer[1000];
    >>
    >>fputs(&buffer, stdout);
    >>}
    >>
    >>gcc -c test.c
    >>
    >>foo.c: In function `foo':
    >>foo.c:6: warning: passing arg 1 of `fputs' from incompatible pointer type
    >>
    >>What version of gcc are you using? This isn't what I call "compiling
    >>cleanly".

    >
    >
    > Interesting! I'm using Dev-C++ and, according to a gcc -v in \dev-cpp\bin
    > it's also 3.4.2.
    >
    > Ahhhhh - very red faced!
    >
    > In an attempt to show a clean example, I [um] edited out a cast!
    >
    > fputs((const char *)&buffer, echoFP);
    >

    *rolls eyes*

    > Ok lesson learned - like I can now see why that wasn't such a great idea!
    >
    > However - I say to myself "well, in that case, that line of code was surely
    > never executed!". So, I took out the newly inserted [0], and put it back to
    > its original and inserted an extra puts():
    >
    > puts("yup");
    > fputs((const char *)&buffer, echoFP);
    >
    > The code runs fine.
    >

    Does it now? Is (opt & out_fle) true when the function is called? What
    file is being written to? Open it and see if it contains what you expect
    or garbage.

    My money's on the latter.

    &buffer points to valid memory. It just doesn't point to what it should
    point: the contents of buffer. Instead it points to the variable buffer
    itself, which is probably somewhere on the stack. fputs() will try to
    interpret this as a string, which has a good chance of succeeding, since
    the stack will probably contain a NUL somewhere and end the output
    before things can get too bad.

    > Here's the whole function [probably going to regret this; although it's not
    > my code!] - used as a kind of printf/fprint etc.
    >
    >
    > /* Used to output stuff to the console and, optionally, to a file.
    > */
    > static void out(int opt, const char * format, ...)
    > {
    > /* Potential for buffer overrun here: but *unlikely*. Maybe work a
    > decent malloc in here in the future though!
    > */
    > auto char buffer[1000];
    >

    auto? Now there's something you don't see every day. The comment is, of
    course, lame. "In the future" means "never", or "when disaster has
    struck". :)

    > auto va_list ap;
    >
    > va_start(ap, format);
    >
    > /* Output to buffer according to what's passed in format and ap (no
    > matter what).
    > */
    > vsprintf(&buffer[0], format, ap);
    >

    Should be
    vsnprintf(buffer, sizeof buffer, format, ap);
    to prevent overflow.

    va_end should go here. See later.

    > /* stdout output.
    > */
    > if(opt & out_std)
    > {
    > puts("here");
    > fputs((const char *)&buffer, stdout);


    Wrong. Bad. Evil. Should indeed be buffer or &buffer[0] if you insist.
    Since this was done right not a few lines ago I have no clue why this
    was messed up. Sounds like a case of "compiler complains, let me insert
    a cast rather than looking at the solution".

    > }
    >
    > /* File output if fp points to something.
    > */
    > if(opt & out_fle)
    > {
    > if(echoFP != NULL)
    > {
    > fputs(&buffer[0], echoFP);
    > fflush(echoFP);
    > }
    > else
    > {
    > out(out_err, "function 'out' called with out_fle, but file
    > pointer is invalid!");


    Function calls itself which is mildly dangerous. If ever a mistake is
    made in invoking the function for reporting an error in the function,
    the recursion will never end. This is not as far-fetched as it sounds.

    Function should be split up. More maintainable and more versatile.

    > }
    > }
    >
    > /* stderr output.
    > */
    > if(opt & out_err)
    > {
    > fputs((const char *)&buffer[0], stderr);


    Cast should be removed.

    > }
    >
    > /* Invalid flags given? This is not a totally exhaustive test as
    > opt_??? are
    > static const int out_std = 1;
    > static const int out_err = 2;
    > static const int out_fle = 4;
    > static const int out_reg = out_std | out_fle;
    > static const int opt_all = out_err | out_std | out_fle;
    > */
    > if(opt < 1 || opt > opt_all)
    > {
    > /* Better report this!
    > */
    > out(out_err, "function 'out' called using opt of %d: which is
    > invalid", opt);
    > }
    >
    > fflush(stdout);
    > fflush(stderr);
    >

    Silly. Why is the file flushed in the if-branch in case of (opt &
    out_file), but not stdout and stderr? Lines should be moved to the
    relevant places.

    > va_end(ap);


    va_end should appear as near to va_start as possible, to prevent
    mistakes. There's no need to defer it to the end of the function.

    S.
     
    Skarmander, Oct 7, 2005
    #8
  9. "pemo" <> writes:
    >> gcc (GCC) 3.4.2 (mingw-special)
    >> Copyright (C) 2004 Free Software Foundation, Inc.
    >> This is free software; see the source for copying conditions. There is NO
    >> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
    >> PURPOSE.
    >>
    >> foo.c:
    >> #include <stdio.h>
    >>
    >> void foo() {
    >> char buffer[1000];
    >>
    >> fputs(&buffer, stdout);
    >> }
    >>
    >> gcc -c test.c
    >>
    >> foo.c: In function `foo':
    >> foo.c:6: warning: passing arg 1 of `fputs' from incompatible pointer type
    >>
    >> What version of gcc are you using? This isn't what I call "compiling
    >> cleanly".

    >
    > Interesting! I'm using Dev-C++ and, according to a gcc -v in \dev-cpp\bin
    > it's also 3.4.2.
    >
    > Ahhhhh - very red faced!
    >
    > In an attempt to show a clean example, I [um] edited out a cast!
    >
    > fputs((const char *)&buffer, echoFP);
    >
    > Ok lesson learned - like I can now see why that wasn't such a great idea!


    Yes, that was a bad idea -- but let's look into why it seems to work.
    (You might already know this.)

    The expression "buffer" (without the quotes, of course) is an array
    name, which is automatically converted to a pointer to the array's
    first element. In this case, it's of type char*, which is exactly
    what you need for the first argument to fputs. So what you really
    want is
    fputs(buffer, stdout);
    or
    fputs(buffer, echoFP);

    An array name is *not* converted to a pointer to its first element
    if it's the operand of a unary "&" or "sizeof" operator. So &buffer
    is a pointer to the array, not to its first element; the type is
    char(*)[1000], or pointer-to-array-of-1000-char. You then cast
    this pointer to "const char *", which almost certainly gives you
    a pointer to the first element of the array. The expressions
    "buffer" and "&buffer" are of different types (pointer-to-char
    vs. pointer-to-array), but they both (loosely speaking) have the same
    value, the address of the first byte of the object "buffer".

    Incidentally, the "const" is superfluous; the formal parameter is
    declared const, but the actual argument doesn't need to be.

    There might be cases where the conversion from pointer-to-array
    to pointer-to-char might not give you the value you want. I'm too
    lazy to analyze the wording of the standard to determine just what's
    guaranteed and what isn't -- and you probably should be as well.
    Just use "buffer"; it's both simpler and safer.

    Also, the first argument to fputs is expected to be a pointer to
    a string (i.e., it needs to be terminated with a '\0' character).
    I'm too lazy to go through the code you posted to confirm that buffer
    will always be properly terminated -- but you shouldn't be.

    One more thing: the "auto" keyword is a relic of ancient C history.
    There never any need to use it.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Oct 7, 2005
    #9
    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. =?ISO-8859-1?Q?Philipp_Cla=DFen?=

    Open watcom supporting C++ STL

    =?ISO-8859-1?Q?Philipp_Cla=DFen?=, Sep 1, 2003, in forum: C++
    Replies:
    1
    Views:
    562
    Pavel Vozenilek
    Sep 1, 2003
  2. alex
    Replies:
    1
    Views:
    602
    Christopher Benson-Manica
    Apr 16, 2004
  3. Spike

    Watcom and ELF...

    Spike, Jul 23, 2004, in forum: C++
    Replies:
    1
    Views:
    421
    Christopher Benson-Manica
    Jul 23, 2004
  4. Basat
    Replies:
    0
    Views:
    387
    Basat
    Dec 1, 2004
  5. Replies:
    2
    Views:
    426
    John Carter
    Jan 10, 2005
Loading...

Share This Page