comp.lang.ada
 help / color / mirror / Atom feed
* type Foo_ptr in new void*;
@ 2001-07-29  4:31 Tomasz Wegrzanowski
  2001-07-29  5:56 ` tmoran
  2001-07-29 14:12 ` Florian Weimer
  0 siblings, 2 replies; 19+ messages in thread
From: Tomasz Wegrzanowski @ 2001-07-29  4:31 UTC (permalink / raw)


I want to use C library from Ada.

C function/procedures are like:

Foo *foo_new(some args);
void foo_delete(Foo*);
void foo_some_operation(Foo*,some args);
xyz foo_some_function(Foo*,some args);

Of course gc is by hand.

How should I typedef Foo* ?



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-29  4:31 type Foo_ptr in new void*; Tomasz Wegrzanowski
@ 2001-07-29  5:56 ` tmoran
  2001-07-29  8:57   ` Tomasz Wegrzanowski
  2001-07-29 14:12 ` Florian Weimer
  1 sibling, 1 reply; 19+ messages in thread
From: tmoran @ 2001-07-29  5:56 UTC (permalink / raw)


> Foo *foo_new(some args);
> void foo_delete(Foo*);
> void foo_some_operation(Foo*,some args);
> xyz foo_some_function(Foo*,some args);
>
> How should I typedef Foo* ?

  Presumably you "typedef Foo" in the C code in normal C style.
If you are wondering how to describe these C functions in Ada,
from the implementation advice in ARM B.3(67 .. 70), as given
at www.adapower.com:

4.An Ada in parameter of an access-to-object type with designated type
  T is passed as a t* argument to a C function, where t is the C type
  corresponding to the Ada type T.
5.An Ada access T parameter, or an Ada out or in out parameter of an
  elementary type T, is passed as a t* argument to a C function, where t
  is the C type corresponding to the Ada type T. In the case of an
  elementary out or in out parameter, a pointer to a temporary copy is
  used to preserve by-copy semantics.
6.An Ada parameter of a record type T, of any mode, is passed as a t*
  argument to a C function, where t is the C struct corresponding to the
  Ada type T.
7.An Ada parameter of an array type with component type T, of any
  mode, is passed as a t* argument to a C function, where t is the C
  type corresponding to the Ada type T.

So given
  type Foo is record ...
  type Foo_Pointer is access Foo;

> Foo *foo_new(some args);
    function foo_new(someargs : sometype) return Foo_Pointer;
> void foo_delete(Foo*);
    procedure foo_delete(Param : in out Foo);
> void foo_some_operation(Foo*,some args);
    procedure foo_some_operation(Param : in out Foo; someargs : in sometype);
> xyz foo_some_function(Foo*,some args);
    function foo_some_function(P : Foo_Pointer; someargs : sometype)
      return xyz;

There are other ways, for instance
    procedure foo_delete(Param : access Foo);



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-29  5:56 ` tmoran
@ 2001-07-29  8:57   ` Tomasz Wegrzanowski
  2001-07-29 12:26     ` Marc A. Criley
  2001-07-29 13:40     ` Dale Stanbrough
  0 siblings, 2 replies; 19+ messages in thread
From: Tomasz Wegrzanowski @ 2001-07-29  8:57 UTC (permalink / raw)


In article <TzN87.10780$Kd7.6085799@news1.rdc1.sfba.home.com>, tmoran@acm.org wrote:
> So given
>   type Foo is record ...
>   type Foo_Pointer is access Foo;

I can't do this.
Foo is supposed to be used only as a pointer.
I don't know if newer version of library will use the same Foo.



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-29  8:57   ` Tomasz Wegrzanowski
@ 2001-07-29 12:26     ` Marc A. Criley
  2001-07-30  1:05       ` Tomasz Wegrzanowski
  2001-07-29 13:40     ` Dale Stanbrough
  1 sibling, 1 reply; 19+ messages in thread
From: Marc A. Criley @ 2001-07-29 12:26 UTC (permalink / raw)


Tomasz Wegrzanowski wrote:
> 
> In article <TzN87.10780$Kd7.6085799@news1.rdc1.sfba.home.com>, tmoran@acm.org wrote:
> > So given
> >   type Foo is record ...
> >   type Foo_Pointer is access Foo;
> 
> I can't do this.
> Foo is supposed to be used only as a pointer.
> I don't know if newer version of library will use the same Foo.

In tmoran's post, wherever you saw "in out Foo", change it to "in
Foo_Pointer".

In order to declare a pointer to a type, you have to have that type's
definition.  Even C requires that for "foo*" there be some declaration
of "foo".

Marc A. Criley
Senior Staff Engineer
Quadrus Corporation
www.quadrus.com



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-29  8:57   ` Tomasz Wegrzanowski
  2001-07-29 12:26     ` Marc A. Criley
@ 2001-07-29 13:40     ` Dale Stanbrough
  1 sibling, 0 replies; 19+ messages in thread
From: Dale Stanbrough @ 2001-07-29 13:40 UTC (permalink / raw)


Tomasz Wegrzanowski wrote:

> I can't do this.
> Foo is supposed to be used only as a pointer.
> I don't know if newer version of library will use the same Foo.

One possibility is...
   subtype Foo is System.Address;

(or just use System.Address).


You could also declare a pointer to <anytype>, and use unchecked
conversion back and forth to the pointer types that you want.

Dale



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-29  4:31 type Foo_ptr in new void*; Tomasz Wegrzanowski
  2001-07-29  5:56 ` tmoran
@ 2001-07-29 14:12 ` Florian Weimer
  1 sibling, 0 replies; 19+ messages in thread
From: Florian Weimer @ 2001-07-29 14:12 UTC (permalink / raw)


taw@pb220.legnica.sdi.tpnet.pl (Tomasz Wegrzanowski) writes:

> How should I typedef Foo* ?

What is 'Foo'? 'void'?

In this case, use the following, which is guaranteed to be portable:

        type Foo_ptr is new Interfaces.C.Strings.chars_ptr;



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-29 12:26     ` Marc A. Criley
@ 2001-07-30  1:05       ` Tomasz Wegrzanowski
  2001-07-30  1:20         ` tmoran
  2001-07-30  2:09         ` James Rogers
  0 siblings, 2 replies; 19+ messages in thread
From: Tomasz Wegrzanowski @ 2001-07-30  1:05 UTC (permalink / raw)


In article <3B63F48A.2E2642C6@earthlink.net>, Marc A. Criley wrote:
>> I can't do this.
>> Foo is supposed to be used only as a pointer.
>> I don't know if newer version of library will use the same Foo.
> 
> In tmoran's post, wherever you saw "in out Foo", change it to "in
> Foo_Pointer".
> 
> In order to declare a pointer to a type, you have to have that type's
> definition.  Even C requires that for "foo*" there be some declaration
> of "foo".

Not true.
You can use `struct Foo *' without declaring `struct Foo'.
You can `typedef struct Foo Foo_t;' or `typedef struct Foo *Foo_p;'
and use Foo_t and Foo_p w/o declaring `struct Foo'.



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-30  1:05       ` Tomasz Wegrzanowski
@ 2001-07-30  1:20         ` tmoran
  2001-07-30  2:09         ` James Rogers
  1 sibling, 0 replies; 19+ messages in thread
From: tmoran @ 2001-07-30  1:20 UTC (permalink / raw)


        type Foo_ptr is new Interfaces.C.Strings.chars_ptr;
>You can use `struct Foo *' without declaring `struct Foo'.
  That's like
    type Foo;
    type Foo_Pointer is access Foo;
except that in Ada you would need a full declaration of Foo eventually.
In any case, clearly if you don't know the structure of a Foo, but only
pass around pointers to them, then the suggestion
    type Foo_ptr is new  Interfaces.C.Strings.chars_ptr;
seems to fit.  Any problems with that?



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-30  1:05       ` Tomasz Wegrzanowski
  2001-07-30  1:20         ` tmoran
@ 2001-07-30  2:09         ` James Rogers
  2001-07-30  2:36           ` Warren W. Gay VE3WWG
                             ` (2 more replies)
  1 sibling, 3 replies; 19+ messages in thread
From: James Rogers @ 2001-07-30  2:09 UTC (permalink / raw)


Tomasz Wegrzanowski wrote:
> 
> In article <3B63F48A.2E2642C6@earthlink.net>, Marc A. Criley wrote:
> >> I can't do this.
> >> Foo is supposed to be used only as a pointer.
> >> I don't know if newer version of library will use the same Foo.
> >
> > In tmoran's post, wherever you saw "in out Foo", change it to "in
> > Foo_Pointer".
> >
> > In order to declare a pointer to a type, you have to have that type's
> > definition.  Even C requires that for "foo*" there be some declaration
> > of "foo".
> 
> Not true.
> You can use `struct Foo *' without declaring `struct Foo'.
> You can `typedef struct Foo Foo_t;' or `typedef struct Foo *Foo_p;'
> and use Foo_t and Foo_p w/o declaring `struct Foo'.

Yes, you are correct. C does allow you to forward declare a structure
or a pointer without ever completing the definition. This is one of
the nasty capabilities "provided" by C. You can even create an array
of Foo *. However, pointer arithmetic from the start of this array
produces unspecified behavior. What is the sizeof Foo? Since it is
undefined, there is no correct answer to that question. Without a
proper definition of the sizeof Foo, there can be no reliable pointer
arithmetic.

In other words, you can declare some wonderful data structures in C
based on incomplete type definitions. Unfortunately, a program built
upon such a structure is neither reliable nor portable.

Ada does not allow you to compile a program with an incomplete type
definition. There is no equivalent because the existence of an
equivalent to this C capability would only introduce errors in your
program. There is nothing positive that can be achieved by allowing
a program to be incompletely specified.

I first realized the differences between C and Ada in this respect
when first learning Ada to support the development of debuggers for
in circuit emulators in 1994. I had to produce programs exhibiting
every data type you can produce from each language so that the
symbolic debug output of compilers, and recognition of the debuggers
could be verified. There was never a version of Ada that supported
incomplete type definition. 

Jim Rogers
Colorado Springs, Colorado USA



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-30  2:09         ` James Rogers
@ 2001-07-30  2:36           ` Warren W. Gay VE3WWG
  2001-07-30  3:10             ` James Rogers
  2001-07-31  1:21           ` Tomasz Wegrzanowski
  2001-07-31  4:56           ` Darren New
  2 siblings, 1 reply; 19+ messages in thread
From: Warren W. Gay VE3WWG @ 2001-07-30  2:36 UTC (permalink / raw)


James Rogers wrote:
> Tomasz Wegrzanowski wrote:
> > In article <3B63F48A.2E2642C6@earthlink.net>, Marc A. Criley wrote:
> > >> I can't do this.
> > >> Foo is supposed to be used only as a pointer.
> > >> I don't know if newer version of library will use the same Foo.
> > >
> > > In tmoran's post, wherever you saw "in out Foo", change it to "in
> > > Foo_Pointer".
> > >
> > > In order to declare a pointer to a type, you have to have that type's
> > > definition.  Even C requires that for "foo*" there be some declaration
> > > of "foo".
> >
> > Not true.
> > You can use `struct Foo *' without declaring `struct Foo'.
> > You can `typedef struct Foo Foo_t;' or `typedef struct Foo *Foo_p;'
> > and use Foo_t and Foo_p w/o declaring `struct Foo'.
> 
> Yes, you are correct. C does allow you to forward declare a structure
> or a pointer without ever completing the definition. This is one of
> the nasty capabilities "provided" by C. You can even create an array
> of Foo *. However, pointer arithmetic from the start of this array
> produces unspecified behavior. What is the sizeof Foo? Since it is
> undefined, there is no correct answer to that question. Without a
> proper definition of the sizeof Foo, there can be no reliable pointer
> arithmetic.

I don't think your "unspecified behavior" assertion is truly fair here.
I believe that when you reach a point in the C/C++ compile where 
pointer arithmetic is required on the "undefined type", you will get
a compile error. The compiler will not generate code that does 
"undefined behaviour" here. If there is any further doubt about it,
I am sure this can be tested with a short example program.

> In other words, you can declare some wonderful data structures in C
> based on incomplete type definitions. Unfortunately, a program built
> upon such a structure is neither reliable nor portable.

Sad, but true. What sometimes happens, is that the C programmer wants
the application to see an "opaque type", and so presents a different
type to the user (by include file) than the original structure. If
this "proxy" is incorrectly defined, its size can be wrong, causing
of course, much "havoc" under the right circumstances. Ada of course,
provides a better model for visibility.

> Ada does not allow you to compile a program with an incomplete type
> definition. There is no equivalent because the existence of an
> equivalent to this C capability would only introduce errors in your
> program. There is nothing positive that can be achieved by allowing
> a program to be incompletely specified.

Ada does permit you to define an incomplete type as well, but the
condition is that it must be defined eventually. I agree that enforcing
its later definition, is a good thing.

-- 
Warren W. Gay VE3WWG
http://members.home.net/ve3wwg



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-30  2:36           ` Warren W. Gay VE3WWG
@ 2001-07-30  3:10             ` James Rogers
  2001-07-31  2:14               ` Warren W. Gay VE3WWG
  0 siblings, 1 reply; 19+ messages in thread
From: James Rogers @ 2001-07-30  3:10 UTC (permalink / raw)


"Warren W. Gay VE3WWG" wrote:
> 
> I don't think your "unspecified behavior" assertion is truly fair here.
> I believe that when you reach a point in the C/C++ compile where
> pointer arithmetic is required on the "undefined type", you will get
> a compile error. The compiler will not generate code that does
> "undefined behaviour" here. If there is any further doubt about it,
> I am sure this can be tested with a short example program.

Your assertion may be true for C++ compilers, but it was not true
for C compilers in the early 1990s.

> Ada does permit you to define an incomplete type as well, but the
> condition is that it must be defined eventually. I agree that enforcing
> its later definition, is a good thing.

Let's be a little more precise here. Ada does not allow you to define
incomplete types. It allows you to define unconstrained types.
There is a real difference. All Ada objects are fully defined.
You cannot make an unconstrained instance of an unconstrained type.

Jim Rogers
Colorado Springs, Colorado USA



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-30  2:09         ` James Rogers
  2001-07-30  2:36           ` Warren W. Gay VE3WWG
@ 2001-07-31  1:21           ` Tomasz Wegrzanowski
  2001-07-31  3:06             ` James Rogers
  2001-07-31  4:56           ` Darren New
  2 siblings, 1 reply; 19+ messages in thread
From: Tomasz Wegrzanowski @ 2001-07-31  1:21 UTC (permalink / raw)


In article <3B64C26F.C195B4E0@worldnet.att.net>, James Rogers wrote:
> Yes, you are correct. C does allow you to forward declare a structure
> or a pointer without ever completing the definition. This is one of
> the nasty capabilities "provided" by C. You can even create an array
> of Foo *. However, pointer arithmetic from the start of this array
> produces unspecified behavior. What is the sizeof Foo? Since it is
> undefined, there is no correct answer to that question. Without a
> proper definition of the sizeof Foo, there can be no reliable pointer
> arithmetic.

Correct answer is compilation error.
It's illegal to do pointer arith on void* or incomplete types.

> In other words, you can declare some wonderful data structures in C
> based on incomplete type definitions. Unfortunately, a program built
> upon such a structure is neither reliable nor portable.

It's both portable and reliable.

> Ada does not allow you to compile a program with an incomplete type
> definition. There is no equivalent because the existence of an
> equivalent to this C capability would only introduce errors in your
> program. There is nothing positive that can be achieved by allowing
> a program to be incompletely specified.

Sure, if your favourite language has no feature X,
then feature X is useless.

Incomplete types warrant opacity.



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-30  3:10             ` James Rogers
@ 2001-07-31  2:14               ` Warren W. Gay VE3WWG
  0 siblings, 0 replies; 19+ messages in thread
From: Warren W. Gay VE3WWG @ 2001-07-31  2:14 UTC (permalink / raw)


James Rogers wrote:
> "Warren W. Gay VE3WWG" wrote:
> >
> > I don't think your "unspecified behavior" assertion is truly fair here.
> > I believe that when you reach a point in the C/C++ compile where
> > pointer arithmetic is required on the "undefined type", you will get
> > a compile error. The compiler will not generate code that does
> > "undefined behaviour" here. If there is any further doubt about it,
> > I am sure this can be tested with a short example program.
> 
> Your assertion may be true for C++ compilers, but it was not true
> for C compilers in the early 1990s.

I've been using C for a long time, and I've used a number of C
compilers. In that experience, I've never seen it compile
pointer arithmetic on non-defined pointer types (you'll get a 
compiler error at the point where the arithmetic is required).

If you can site a specific example, I might believe it. Even then,
I'd have to say that it was unusual and attributable to a bad C
compiler.

> > Ada does permit you to define an incomplete type as well, but the
> > condition is that it must be defined eventually. I agree that enforcing
> > its later definition, is a good thing.
> 
> Let's be a little more precise here. Ada does not allow you to define
> incomplete types. 

You know what I meant. However, for everyone else, here is precisely
what I was trying to describe:

package X is

   type My_Type;        -- Not fully defined....
   type My_Type_Ptr is access all My_Type;

   -- Here My_Type is still _not_ defined yet...

   type My_Type is
      record
         Name :   String(1..8);
         Next :   My_Type_Ptr;      -- Ptr to next
      end record;

end X;

Between the statement "type My_Type;" and the full declaration at the
bottom, like C, you can have a forward referencing type, where it is
not fully defined.

Note that in this case, there is no other way to define the
My_Type_Ptr member Next in My_Type. This is why it is permitted.

-- 
Warren W. Gay VE3WWG
http://members.home.net/ve3wwg



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-31  1:21           ` Tomasz Wegrzanowski
@ 2001-07-31  3:06             ` James Rogers
  2001-07-31  5:02               ` Warren W. Gay VE3WWG
  2001-07-31  7:22               ` Florian Weimer
  0 siblings, 2 replies; 19+ messages in thread
From: James Rogers @ 2001-07-31  3:06 UTC (permalink / raw)


Tomasz Wegrzanowski wrote:
> 
> In article <3B64C26F.C195B4E0@worldnet.att.net>, James Rogers wrote:
> > Yes, you are correct. C does allow you to forward declare a structure
> > or a pointer without ever completing the definition. This is one of
> > the nasty capabilities "provided" by C. You can even create an array
> > of Foo *. However, pointer arithmetic from the start of this array
> > produces unspecified behavior. What is the sizeof Foo? Since it is
> > undefined, there is no correct answer to that question. Without a
> > proper definition of the sizeof Foo, there can be no reliable pointer
> > arithmetic.
> 
> Correct answer is compilation error.
> It's illegal to do pointer arith on void* or incomplete types.

It is illegal, but not necessarily caught by the compiler.
This means that the correct answer is not compilation error.
C compilers are actually pretty primitive in their understanding of
data type completion. They rely on highly intelligent linkers to
find all the completions. Unfortunately, linker diagnostic messages
are a lot less useful than compiler diagnostic messages. One reason
is that the linker has no understanding of source code line numbers.
It cannot tell you where the problem occured beyond the name of the
object file it came from. Given the C #include technology, you cannot
even directly relate the object file name with the source file name
in all cases. A single object file could have been created from
one or several source files.

Even more problems arise when using shared libraries or DLLs. In
that case the linker cannot find all the required pieces. Only the
program loader will find them. Your compiler and linker may
execute without error. Your loader will be left to try to
identify all the missing pieces. Loader error messages are even
poorer than linker error messages.

What does it mean, then, when a function returns a void*?
You are allowed to cast that void* to any other pointer type you want.
Once cast, you are allowed to perform pointer arithmetic on it.
If you do not TRULY know the type of the data pointed to by a void*,
and then you cast it to some type, expecting correct results, you 
will sometimes get a nasty surprise. Pointer arithmetic will be
performed, but your view of the data will be incorrect due to 
poor alignment problems.

> 
> > In other words, you can declare some wonderful data structures in C
> > based on incomplete type definitions. Unfortunately, a program built
> > upon such a structure is neither reliable nor portable.
> 
> It's both portable and reliable.

It is portable because it causes the same kinds of problems wherever
used. You can rely on this feature to be dangerous. For instance,
an array of incomplete data types, or pointers to the same, will
cause a violation of the rules you state above. That array can be
created, but not manipulated. In C, all array element access
involves pointer arithmetic. This is true even when using array
indexing directly. The compiler simply substitutes pointer arithmetic
for the indexing notation.

> 
> > Ada does not allow you to compile a program with an incomplete type
> > definition. There is no equivalent because the existence of an
> > equivalent to this C capability would only introduce errors in your
> > program. There is nothing positive that can be achieved by allowing
> > a program to be incompletely specified.
> 
> Sure, if your favourite language has no feature X,
> then feature X is useless.

Ada does not have this feature because its danger was judged to 
outweigh its value. That does not make this feature useless. It only
makes it unsafe.

> Incomplete types warrant opacity.

This is important in C because of its lack of private data types.
More modern languages achieve opacity without sacrificing program
safety. 

Jim Rogers
Colorado Springs, Colorado USA



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-30  2:09         ` James Rogers
  2001-07-30  2:36           ` Warren W. Gay VE3WWG
  2001-07-31  1:21           ` Tomasz Wegrzanowski
@ 2001-07-31  4:56           ` Darren New
  2001-08-04  6:05             ` David Thompson
  2 siblings, 1 reply; 19+ messages in thread
From: Darren New @ 2001-07-31  4:56 UTC (permalink / raw)


>  You can even create an array
> of Foo *. However, pointer arithmetic from the start of this array
> produces unspecified behavior. 

Errrr, no it doesn't.

> What is the sizeof Foo? 

Irrelevant, if you have an array of Foo*. If you have an array of Foo,
it's relevant.

> Since it is
> undefined, there is no correct answer to that question. Without a
> proper definition of the sizeof Foo, there can be no reliable pointer
> arithmetic.

Right. That's why you can't do pointer arithmetic on a Foo* without
defining Foo.

Which is not to say that Ada isn't superior to C in this respect. 

But what do you think a compiler is going to do if you index an array of
Foo without defining Foo? Just randomly make up a sizeof(Foo) from whole
cloth? There's probably something in the standard about this.

-- 
Darren New / Senior MTS & Free Radical / Invisible Worlds Inc.
San Diego, CA, USA (PST). Cryptokeys on demand. dnew@san.rr.com
          Only a WIMP puts wallpaper on his desktop.



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-31  3:06             ` James Rogers
@ 2001-07-31  5:02               ` Warren W. Gay VE3WWG
  2001-07-31  7:22               ` Florian Weimer
  1 sibling, 0 replies; 19+ messages in thread
From: Warren W. Gay VE3WWG @ 2001-07-31  5:02 UTC (permalink / raw)


James Rogers wrote:
> Tomasz Wegrzanowski wrote:
> > In article <3B64C26F.C195B4E0@worldnet.att.net>, James Rogers wrote:
> > > Yes, you are correct. C does allow you to forward declare a structure
> > > or a pointer without ever completing the definition. This is one of
> > > the nasty capabilities "provided" by C. You can even create an array
> > > of Foo *. However, pointer arithmetic from the start of this array
> > > produces unspecified behavior. What is the sizeof Foo? Since it is
> > > undefined, there is no correct answer to that question. Without a
> > > proper definition of the sizeof Foo, there can be no reliable pointer
> > > arithmetic.
> >
> > Correct answer is compilation error.
> > It's illegal to do pointer arith on void* or incomplete types.

Yes, that is correct (that it is illegal).

> It is illegal, but not necessarily caught by the compiler.
> This means that the correct answer is not compilation error.
> C compilers are actually pretty primitive in their understanding of
> data type completion. They rely on highly intelligent linkers to
> find all the completions. Unfortunately, linker diagnostic messages

Huh? What does linking have to do with pointer arithmetic and "incomplete
types"?  I remember some bad C compilers (Aztec C on the Mac comes to
mind), but even the ever forgiving HP C compiler would catch this 
kind of stuff (incomplete type and pointer arithmetic that is).

As far as allowing "undefined pointer arithmetic" without a compiler
warning or error, you need to cite specific compiler brands, and 
show examples. Otherwise this is just rubbish, as far as I can see.
I've only seen error messages when pointer arithmetic is required for
incompletely defined types.

> If you do not TRULY know the type of the data pointed to by a void*,
> and then you cast it to some type, expecting correct results, you
> will sometimes get a nasty surprise. Pointer arithmetic will be
> performed, but your view of the data will be incorrect due to
> poor alignment problems.

Of course. If you cast _any_ pointer to another pointer type, you
cannot expect the arithmetic to be necessarily the same! So what's
the point? All C programmers know this already.

You as the C programmer have said "I know what I'm doing and I want
you the compiler to treat this address as a pointer to type Z, and
by golly, you better do pointer arithmetic according to the Z type."

After that, are you really surprised that the C compiler generates
code that does arithmetic on the pointer by type Z?

> Jim Rogers
> Colorado Springs, Colorado USA

C compilers (as with the C language), do have "issues". But not the
one you've chosen here.

-- 
Warren W. Gay VE3WWG
http://members.home.net/ve3wwg



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-31  3:06             ` James Rogers
  2001-07-31  5:02               ` Warren W. Gay VE3WWG
@ 2001-07-31  7:22               ` Florian Weimer
  1 sibling, 0 replies; 19+ messages in thread
From: Florian Weimer @ 2001-07-31  7:22 UTC (permalink / raw)


James Rogers <jimmaureenrogers@worldnet.att.net> writes:

>> It's illegal to do pointer arith on void* or incomplete types.
> 
> It is illegal, but not necessarily caught by the compiler.

C compilers must issue diagnostics if the source code contains pointer
arithmetic on an incomplete type.

> This means that the correct answer is not compilation error.

It is, read the standard: there is a constraint that pointer
arithmetic shall be done only on pointers to object types (which
excludes function pointers and pointers to incomplete types), and
constraint violations must be detected by the compiler.

> C compilers are actually pretty primitive in their understanding of
> data type completion.

It's not that primitive.

> They rely on highly intelligent linkers to find all the completions.

The C object model certainly does not require any linker support for
incomplete types.  In fact, types never appear in linker input.  (Of
course, there are obscure targets for which these things are not true,
e.g. the x86 target with a segmented memory model, but it's quite hard
for compilers for such targets to conform to the C standard anyway).



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-07-31  4:56           ` Darren New
@ 2001-08-04  6:05             ` David Thompson
  2001-08-05  2:27               ` Warren W. Gay VE3WWG
  0 siblings, 1 reply; 19+ messages in thread
From: David Thompson @ 2001-08-04  6:05 UTC (permalink / raw)


Darren New <dnew@san.rr.com> wrote :
...
> > Since [sizeof a C incomplete struct type namely Foo] is
> > undefined, there is no correct answer to that question. Without a
> > proper definition of the sizeof Foo, there can be no reliable pointer
> > arithmetic.
>
> Right. That's why you can't do pointer arithmetic on a Foo* without
> defining Foo.
>
One thing the previous poster might have been thinking of is
that in C89/90 you could _declare_ as "extern" an array of
an incomplete type; you might also be able to declare/define
a function (formal) parameter as array of incomplete since
that can be "adjusted" to a pointer, and pointer to incomplete
is fine, although the WG response to Defect Report 047 held
that this is not guaranteed; you could also define a typedef
for array-of-incomplete if ultimately used only as above.
You could _define_ (allocate) an actual array object only
with a complete element type.

Since you can't do pointer arithmetic (and thus []) on it,
the only thing you could do with an array-of-incomplete
was pass its address (pointer) to some other code which
_does_ know about the completed type.

In C99, this feature(?) is gone; it is now a constraint (6.7.5.2p1)
on the array declarator that the element type must be complete
in all cases, and thus a required diagnostic if not (see below).
(But even when compilers start supporting C99, I expect some,
maybe many, will still have options to get C89 behavior.)

> Which is not to say that Ada isn't superior to C in this respect.
>
In particular, in C it is the programmer's responsibility to have
different translation units (roughly, source files) use identical
definitions (or nearly so) for a struct type.  It is easy to get this
wrong; the implementation is not required to detect it; and
many, probably most, don't, since the compile+link model
doesn't normally support it, although it would be legal.
(I do know one implementation where the linker checks
that function parameters which are pointers agree on
the _size_ of the target; this doesn't catch all errors,
but does help a good bit.  I think it does so primarily
because it needs this info in the object file for Fortran
and COBOL, and C goes along for the ride.)

Actually writing different definitions in two different sources
is fairly obvious, but there are subtler ways to screw up.
One is to change the definition in a .h file and recompile
some but not all of the .c's that use it; tools like make
help with this.  Another is to have two same-named .h files
in different directories/subtrees and select a wrong one.
A third is to actually include the correct and same .h
but it in turn uses #define's which are set differently
(a coworker recently lost several days to that last;
even a full de novo build doesn't catch or fix it).

> But what do you think a compiler is going to do if you index an array of
> Foo without defining Foo? Just randomly make up a sizeof(Foo) from whole
> cloth? There's probably something in the standard about this.
>
If anyone really cares (from C99 = ANSI/ISO/IEC 9899:1999)
- 6.5.2.1 defines subscripting (partly) in terms of pointer addition
- 6.5.6p2 requires in a constraint that (one) operand of pointer addition
be "to an object type"
- 6.2.5p1 defines "object type" to exclude incomplete types.
(Those places in the standard that want to allow incomplete types
say "object or incomplete type".)
- 6.5.3.4p1 requires in a constraint that sizeof "shall not be applied to
... an incomplete type ..." (sizeof is not actually used in the _definition_
of pointer arithmetic directly, although that's the usual implementation,
only indirectly through 6.2.5p20 array elements are contiguous)
- 5.1.1.3 requires "at least one diagnostic message" if there is
"a violation of any syntax rule or constraint" -- although the standard
doesn't require _useful_ diagnostics; it is only a nonnormative footnote
that it _should_ "identify the nature of, and where possible localize,
each violation."

Having diagnosed a violation, the implementation is permitted
to do anything whatsoever, even continue to translate and execute;
this is Undefined Behavior "on which this International Standard
imposes no requirements" (much like Ada Unbounded Error).
If a compiler writer was silly enough to think that a random (more
likely pseudorandom) sizeof here was a good idea, they could.
More plausible is to just use whatever value happens to be in
some slot of the symbol table that would be correct for a
complete type but isn't valid (wasn't set) for incomplete.

HAND.
--
- David.Thompson 1 now at worldnet.att.net








^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: type Foo_ptr in new void*;
  2001-08-04  6:05             ` David Thompson
@ 2001-08-05  2:27               ` Warren W. Gay VE3WWG
  0 siblings, 0 replies; 19+ messages in thread
From: Warren W. Gay VE3WWG @ 2001-08-05  2:27 UTC (permalink / raw)


David Thompson wrote:
> Darren New <dnew@san.rr.com> wrote :
> ...
> Actually writing different definitions in two different sources
> is fairly obvious, but there are subtler ways to screw up.
> One is to change the definition in a .h file and recompile
> some but not all of the .c's that use it; tools like make
> help with this.  Another is to have two same-named .h files
> in different directories/subtrees and select a wrong one.
> A third is to actually include the correct and same .h
> but it in turn uses #define's which are set differently
> (a coworker recently lost several days to that last;
> even a full de novo build doesn't catch or fix it).

Another way to have this happen, is to have a "private"
definition as the "proper type" which is used internally
by the library, and an incorrect "opaque type" defined 
for public use. Or, this may have been correctly (but not
portably) defined, but did not port correctly to the 
new platform.

-- 
Warren W. Gay VE3WWG
http://members.home.net/ve3wwg



^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2001-08-05  2:27 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-07-29  4:31 type Foo_ptr in new void*; Tomasz Wegrzanowski
2001-07-29  5:56 ` tmoran
2001-07-29  8:57   ` Tomasz Wegrzanowski
2001-07-29 12:26     ` Marc A. Criley
2001-07-30  1:05       ` Tomasz Wegrzanowski
2001-07-30  1:20         ` tmoran
2001-07-30  2:09         ` James Rogers
2001-07-30  2:36           ` Warren W. Gay VE3WWG
2001-07-30  3:10             ` James Rogers
2001-07-31  2:14               ` Warren W. Gay VE3WWG
2001-07-31  1:21           ` Tomasz Wegrzanowski
2001-07-31  3:06             ` James Rogers
2001-07-31  5:02               ` Warren W. Gay VE3WWG
2001-07-31  7:22               ` Florian Weimer
2001-07-31  4:56           ` Darren New
2001-08-04  6:05             ` David Thompson
2001-08-05  2:27               ` Warren W. Gay VE3WWG
2001-07-29 13:40     ` Dale Stanbrough
2001-07-29 14:12 ` Florian Weimer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox