Topic: New ANSI rule breaks code


Author: jzipnick@best.com (Jay Zipnick)
Date: 1995/04/25
Raw View
-----
class foo;

void f3(foo* arr);    // compiles OK
void f4(foo  arr[]);  // <<-- This is illegal
-----

Steve,

Thanks for the explanation as to why this is illegal C/C++. To me it looks
like a case of striving for consistency to an extreme. This is one area
where C++ could have been a *better* C. Here is why I would suggest a
reevaluation:

1) It breaks code. I am guessing the only reason why people haven't
screamed about this yet is that they don't realize it is wrong, and
virtually no compilers are enforcing it yet.

2) Leads to less clear code: I gave an example in which an array of T is
passed to a private member function, and T is a private implementation
detail, so was intentionally declared in the .c file instead of the .h
file. Although this made it through 6 compilers, it is illegal. Given
this, the simplest change I can make is to change the array syntax to
pointer syntax ([] --> *) in my argument list. Now my code is less clear!
This violates various style guidelines such as "Taligent's Guide to
Desiging Programs", page 44.

3) Weakens encapsulation: Alternatively, I can keep the array syntax in my
argument list, but move the declaration of T from my .c file to the .h
file, and include this hidden implemenation detail in the *public*
interfaces. Whether I choose this option or option 2 above, I am faced
with making a bad decision.

An astute reader may point out that the *real* problem is that I am using
an incomplete type to work around the fact that this implementation detail
in the argument of a private member function, *must* be in the class
declaration of the public interfaces. Yes that is the real problem, but
that is something we must live with, and that is not about to change. So
the best solution is to accept that it is technically illegal in C (100%
of a small survey of C++ programmers have been surprised by this), realize
that underneath it all, it is a pointer, so T can be incomplete. Also
realize that virtually all compilers accept this. As bad as it sounds to
be illegal in C and legal in C++, in this case, it makes C++ a better C,
and stops the fallout from the code that will break when this is enforced.

One last argument comes from p. 100 of "The C Programming Language", 2nd
Ed. It states:

    Within f, the parameter declaration can read

       f(int arr[]) { ... }
    or
       f(int *arr) { ... }

Yes, here int is a complete type, but the point is that this is within the
"spirit" of C.





Author: jsa@edg.com (J. Stephen Adamczyk)
Date: 1995/04/25
Raw View
In article <jzipnick-2504951006100001@jzipnick.vip.best.com> jzipnick@best.com (Jay Zipnick) writes:
>class foo;
>void f3(foo* arr);    // compiles OK
>void f4(foo  arr[]);  // <<-- This is illegal
>
>Thanks for the explanation as to why this is illegal C/C++. To me it looks
>like a case of striving for consistency to an extreme. This is one area
>where C++ could have been a *better* C. Here is why I would suggest a
>reevaluation:

Latest information (specifically, DR 110 for C) suggests this construct
is not strictly conforming in C, but no diagnostic is required.  In other
words, implementations are free to make this work the way you want in C.
You as a programmer, however, can't write this code and expect it to
work on all C compilers.

I will ask to have the issue revisited at the next C++ standards meeting.

Steve Adamczyk
Edison Design Group





Author: jzipnick@best.com (Jay Zipnick)
Date: 1995/04/23
Raw View
In article <3n9jli$qhg@ixnews3.ix.netcom.com>, cade@ix.netcom.com (Cade
Roux) wrote:

> It's legal C - it saves declaring somthing as a fixed length argument
> array, and looks more like an array - when it's actually passed as a
> pointer, right?
>
> Something funny's up - which compiler are you having trouble with it
> on?

Which compiler is not the point, the point is that this appears to be a
C++ standards issue. Allegedly all compilers should eventually disallow
this.

The problem (again) is the following code:
-----
class foo;

void f1(int* arr);    // compiles OK
void f2(int  arr[]);  // compiles OK
void f3(foo* arr);    // compiles OK
void f4(foo  arr[]);  // doesn't compile with *new* version of one compiler!!
-----

The code compiles fine with *release* versions of g++ 2.6.3, and the
standard Mac compilers: CFront, PPCC, SCpp, MrCpp, and MW C/C++. I
shouldn't say which update it failed with since officially it hasn't
shipped.

According to the compiler architect it shouldn't compile:

     "void f4(foo  arr[]);" is illegal because foo is incomplete. This is
     not really clear in the ARM but [ANSI C++ draft 01 Feb 1995 8.3.4
     Arrays] says:

     "In a declaration T D where D has the form "D1 [ const-expr(opt) ]"
     ... . T shall not be a reference type, an incomplete type, ...".

I am not picking on any individual compiler. The point is that this
February ANSI change is bad (for all the reasons in the initial posting).
Can
someone who knows why this change was made by ANSI please explain the rationale.





Author: jsa@edg.com (J. Stephen Adamczyk)
Date: 1995/04/24
Raw View
In article <jzipnick-2304952250080001@jzipnick.vip.best.com> jzipnick@best.com (Jay Zipnick) writes:
>class foo;
>void f1(int* arr);    // compiles OK
>void f2(int  arr[]);  // compiles OK
>void f3(foo* arr);    // compiles OK
>void f4(foo  arr[]);  // doesn't compile with *new* version of one compiler!!

I was involved in the discussion on this change, and the reason was for
conformance with C.  Yes, it was our belief that C doesn't allow this
either.  (3.1.2.5 of the ANSI C standard says arrays can only be formed
from object types, which does not include incomplete types; a footnote
confirms that interpretation).

In the case you cite, one could argue that the type of the parameter being
declared is really a pointer to foo, not an array of foo, and therefore the
invalid array type is not formed.  But that's not what the standard words
say.  The WP, for example, says "The type of each parameter is determined
from its own decl-specifier-seq and declarator.  After determining the type
of each parameter, any parameter of type ``array of T'' or ``function
returning T'' is adjusted to be ``pointer to T'' or ``pointer to function
returning T,'' respectively."  In other words, you make the array type,
and then you convert it to a pointer type.  But if you can't make the array
type, it's an error.

I believe that X3J11/WG14 discussed the case

  void f(int[][]);

The issue was the same -- whether the invalid array type existed, even if
just for a fleeting moment before conversion to a pointer type.  My
recollection (and this is recollection, which may be faulty) is that
X3J11 said the type was invalid.  (I couldn't find this issue in my
online records, and it's not addressed in TC1 for C.)

Anyway, that's the reason.  If it can be shown that the example you give
is actually valid ANSI/ISO C, I imagine this issue could be reopened and
changed the other way.

Steve Adamczyk
Edison Design Group