On 9 Apr., 19:16, Diego Martins
> On Apr 9, 2:53 am, Richard Heathfield
>
>
>
>
>
> > Juha Nieminen said:
>
> > > Richard Heathfield wrote:
> > >> lbonaf...@yahoo.com said:
>
> > >>
>
> > >>> And in C, there's absolutely no way to know who's fiddling around wi=
th
> > >>> your struct members because you can't restrict access to them.
>
> > >> Wrong. Maybe *you* can't restrict access to them, but I can, and so c=
an
> > >> quite a few others in comp.lang.c. The technique is not difficult.
>
> > > =A0 I have always detested this kind of argument.
>
> > Let's see whether I can amend it to your liking.
>
> > > "Maybe you can't, but we
> > > who are better than you can",
>
> > Not what I meant. Mr lbonafide said that there's absolutely no way, so I=
> > presume he accepts that he can't do it, and that his inability to do it =
is
> > not in dispute. That doesn't mean I'm "better" than him. It does, howeve=
r,
> > appear to mean that I know something he doesn't - which is easily fixed,=
> > of course.
>
> > > "it's quite easy",
>
> > Aye, it is. Sorry.
>
> > > and then don't even
> > > show this "easy" solution at all
>
> > See below.
>
> > > (which usually involves ugly hacks and
> > > jumping through completely unnecessary hoops).
>
> > Um, it's not /that/ ugly a hack, and I assure you I'll only jump through=
> > *necessary* hoops.
>
> > The technique involves a minimum of three files - the interface (.h), th=
e
> > implementation (.c, which you *don't release*), and the driver, which th=
e
> > user-programmer writes.
>
> > Here is our interface (which we ship):
>
> > #ifndef H_POINT
> > #define H_POINT 1
>
> > #include
>
> > #define POINT_INVALID INT_MIN
>
> > typedef struct point_ point;
>
> > point *point_make(int, int);
> > void point_destroy(point **);
> > int point_setx(point *, int);
> > int point_sety(point *, int);
> > int point_set(point *, int, int);
> > double point_diff(const point *, const point *);
> > #endif
>
> > The important point (if you'll forgive the word) is that the point type =
is
> > declared but *not* defined, so its members are not visible. More about
> > that shortly.
>
> > The totally unimportant point is that this is just an example, and so yo=
u
> > shouldn't expect to see a complete function suite here!
>
> > Implementation file (NOT shipped):
>
> > #include "point.h"
>
> > #include
> > #include
>
> > struct point_
> > {
> > =A0 int x;
> > =A0 int y;
>
> > };
>
> > point *point_make(int x, int y)
> > {
> > =A0 point *new =3D malloc(sizeof *new);
> > =A0 if(new !=3D NULL)
> > =A0 {
> > =A0 =A0 new->x =3D x;
> > =A0 =A0 new->y =3D y;
> > =A0 }
> > =A0 return new;}
>
> > void point_destroy(point **old)
> > {
> > =A0 if(old !=3D NULL)
> > =A0 {
> > =A0 =A0 free(*old);
> > =A0 =A0 *old =3D NULL;
> > =A0 }
>
> > }
>
> > int point_setx(point *p, int x)
> > {
> > =A0 int old =3D POINT_INVALID;
>
> > =A0 if(p !=3D NULL)
> > =A0 {
> > =A0 =A0 old =3D p->x;
> > =A0 =A0 p->x =3D x;
> > =A0 }
> > =A0 return old;
>
> > }
>
> > int point_sety(point *p, int y)
> > {
> > =A0 int old =3D POINT_INVALID;
>
> > =A0 if(p !=3D NULL)
> > =A0 {
> > =A0 =A0 old =3D p->y;
> > =A0 =A0 p->y =3D y;
> > =A0 }
> > =A0 return old;
>
> > }
>
> > int point_set(point *p, int x, int y)
> > {
> > =A0 int rc =3D POINT_INVALID;
>
> > =A0 if(p !=3D NULL)
> > =A0 {
> > =A0 =A0 rc =3D 0;
> > =A0 =A0 p->x =3D x;
> > =A0 =A0 p->y =3D y;
> > =A0 }
> > =A0 return rc;
>
> > }
>
> > double point_diff(const point *pa, const point *pb)
> > {
> > =A0 double d =3D 0.0;
>
> > =A0 if(pa !=3D NULL && pb !=3D NULL)
> > =A0 {
> > =A0 =A0 double xd =3D pa->x - pb->x;
> > =A0 =A0 double yd =3D pa->y - pb->y;
> > =A0 =A0 d =3D sqrt(xd * xd + yd * yd);
> > =A0 }
>
> > =A0 return d;
>
> > }
>
> > We don't ship this to the user. Instead, we compile it, put the resultin=
g
> > object code into a library, and ship the library.
>
> > Test driver:
>
> > #include "point.h"
>
> > #include
>
> > int main(void)
> > {
> > =A0 point *p1 =3D point_make(1, 1);
> > =A0 if(p1 !=3D NULL)
> > =A0 {
> > =A0 =A0 point *p2 =3D point_make(4, 5);
> > =A0 =A0 if(p2 !=3D NULL)
> > =A0 =A0 {
> > =A0 =A0 =A0 double d =3D point_diff(p1, p2);
> > =A0 =A0 =A0 printf("The hypotenuse is %f\n", d);
> > =A0 =A0 =A0 point_destroy(&p2);
> > =A0 =A0 }
> > =A0 =A0 point_destroy(&p1);
> > =A0 }
> > =A0 return 0;
>
> > }
>
> > This works. (Try it.)
>
> > The following test driver does *not* work:
>
> > #include "point.h"
>
> > #include
>
> > int main(void)
> > {
> > =A0 point *p1 =3D point_make(1, 1);
> > =A0 size_t size =3D sizeof *p1; /* can't do this */
> > =A0 point instance; /* can't do this either */
>
> > =A0 instance.x =3D 42; /* or this! */
>
> > =A0 if(p1 !=3D NULL)
> > =A0 {
> > =A0 =A0 point *p2 =3D point_make(4, 5);
> > =A0 =A0 if(p2 !=3D NULL)
> > =A0 =A0 {
> > =A0 =A0 =A0 double d =3D point_diff(p1, p2);
> > =A0 =A0 =A0 printf("The hypotenuse is %f\n", d);
> > =A0 =A0 =A0 point_destroy(&p2);
> > =A0 =A0 }
> > =A0 =A0 point_destroy(&p1);
> > =A0 }
> > =A0 return 0;
>
> > }
>
> > When I compile this, I get the following errors:
>
> > driver.c: In function `main':
> > driver.c:8: dereferencing pointer to incomplete type
> > driver.c:9: storage size of `instance' isn't known
>
> > Thus, you *can* restrict access to members of a struct, QED.
>
> > > =A0 Reminds me of the C-hackers who insist that it's "easy" and "feasi=
ble"
> > > to use dynamically bound "member functions" in structs, as if that
> > > somehow made C as good as C++ (yet the big problem with that hack is
> > > that each "member function" of the struct increases the size of the
> > > struct, which in many cases is a completely useless waste and makes th=
at
> > > struct larger and more inefficient).
>
> >
> > bait. C and C++ are different languages with different goals and differe=
nt
> > user bases. To claim that one is "better" than another, without specifyi=
ng
> > in what way it is better and for whom, is to fail to understand that the=
re
> > are good reasons for having more than one programming language.
>
> > Whilst it /is/ not only feasible but even easy to use dynamically bound
> > member functions in structs, it is certainly true that this incurs an
> > overhead for the pointer in every instance of the struct, and this cost
> > should be considered when deciding whether or not to pursue this course.=
>
> > The way I resolve this myself is simple - either I'm going to be using a=
> > lot of structs, in which case they're probably going to be in some kind =
of
> > container, so I'll put the pointers in the container instead - which is
> > normally okay because all the structs in any given container are general=
ly
> > going to want to be processed in the same way), or I only have a few, in=
> > which case the overhead is no big deal.
>
> VERY SIMPLE HUH?
> verrryyy eaasyyyyyyy and nooooooooo boilerplaateeee
>
> bah!
>
> I always laugh to coders that loves to work for the computer
> of course most of them does not have childs of wife or even a
> girlfriend ;-)
>
> computers should work to us. they are designed to do that :)
>
> sorry for the ranting, but there are some things I can't admit today
Well... Richards code really is not at all difficult - very much like
the C++ pimpl idiom. So information CAN be hidden in C. Just not as
elegantly as in C++, as I'm sure we all agree.
I remember in my old days writing classes with virutal functions in C.
I thought it was so elegant. Not so anymore - but you can do a lot in
C if you want to.
/Peter