By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,347 Members | 2,113 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,347 IT Pros & Developers. It's quick & easy.

Object-oriented programming in standard ANSI C

P: n/a
Hi,

I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. I'm studying the GObject library and Laurent
Deniau's OOPC framework published on his web site at
http://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html. The approach is
very instructive. I know that I could do much of this stuff with e.g.
C++, but the intellectual challenge of implementing these concepts with
pure ANSI C is relevant to me.

Are you aware of another approaches? Any experience in using such
techniques in production code? The use of GObject seems to be well
implemented in the GNOME world, but I didn't find much about Laurent
Deniau's OOPC. Have you some comments about the strengths and drawbacks
of such techniques?

Many thanks for your valuable help and comments

Best regards

Thierry

Nov 15 '06 #1
Share this Question
Share on Google+
47 Replies


P: n/a


On Nov 15, 6:28 pm, "Thierry Chappuis" <thie...@mujigka.chwrote:
Hi,

I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. I'm studying the GObject library and Laurent
Deniau's OOPC framework published on his web site athttp://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html. The approach is
very instructive. I know that I could do much of this stuff with e.g.
C++, but the intellectual challenge of implementing these concepts with
pure ANSI C is relevant to me.

Are you aware of another approaches? Any experience in using such
techniques in production code? The use of GObject seems to be well
implemented in the GNOME world, but I didn't find much about Laurent
Deniau's OOPC. Have you some comments about the strengths and drawbacks
of such techniques?

Many thanks for your valuable help and comments

Best regards

Thierry
Yeah. This is an interesting topic. In fact, C can NOT fully support
OOP like C++, but we can use some tricks to make it *like* an
object-oriented programming language. For example, we can use
structures to replace classes, use function pointer as a member of a
structure like a method of a class. And in fact, in Linux kernel source
code, there are really such OO ideas applied.

Nov 15 '06 #2

P: n/a
On Nov 15, 10:15 am, "Cong Wang" <xiyou.wangc...@gmail.comwrote:
ThierryYeah. This is an interesting topic. In fact, C can NOT fully support
OOP like C++, but we can use some tricks to make it *like* an
object-oriented programming language. For example, we can use
structures to replace classes, use function pointer as a member of a
structure like a method of a class. And in fact, in Linux kernel source
code, there are really such OO ideas applied.
That's just one of the three requirements for an OO programming
language, encapsulation. The other two are inheritance and
polymorphism, and those are much more difficult to emulate in C. I've
seen inheritance attempted by exploiting the fact that C will let you
cast any type to any other type without complaining. So basically:

struct Parent
{
int a,b;
};

struct Child
{
int a,b;
more variables
};

struct Child2
{
int a,b;
more variables
}

If you want to pass a Child or a Child2 to a function, instead of
making two version of the function (which need different names because
there is no overloading in C), you can make the function take a Parent,
and then pass a Child or a Child2 'c' by saying (Parent)c. I'm not
sure if this just happens to work, or if it is actually defined in the
C standard that the variables of a structure appear in memory in the
order that they are specified in the declaration.

I haven't seen any way to do polymorphism. I guess that's kind of like
templates in C++, although templates are technically not polymorphism,
they are a hack to acheive the effect of polymorphism. This is because
the templates are handled at compile time, and true OO polymorphism is
runtime polymorphism.

Colin K.

Nov 15 '06 #3

P: n/a
raza...@gmail.com wrote:
On Nov 15, 10:15 am, "Cong Wang" <xiyou.wangc...@gmail.comwrote:
ThierryYeah. This is an interesting topic. In fact, C can NOT fully support
OOP like C++, but we can use some tricks to make it *like* an
object-oriented programming language. For example, we can use
structures to replace classes, use function pointer as a member of a
structure like a method of a class. And in fact, in Linux kernel source
code, there are really such OO ideas applied.

That's just one of the three requirements for an OO programming
language, encapsulation. The other two are inheritance and
polymorphism, and those are much more difficult to emulate in C. I've
seen inheritance attempted by exploiting the fact that C will let you
cast any type to any other type without complaining.
<snip>
I haven't seen any way to do polymorphism...
<snip>

But the biggest gain of all in using a true OO enabled language like
C++ is the compiler support for OO constructs. C wasn't designed for
OOP and with increasing availability of C++ compilers for most
non-embedded platforms, it would be wiser to use the latter, (or
another OO language), unless there're strong reasons to favour C, (like
writing low-level system code, or desiring maximum portability etc).

Nov 15 '06 #4

P: n/a
Cong Wang wrote:
Yeah. This is an interesting topic. In fact, C can NOT fully support
OOP like C++,
It doesn't have syntactic support -- and that makes writing OO
code a real bigger -- but you can do polymorphism/inheritance
if you must; I think there's just enough room in the Standard
to make the required machinery legal.

Painful, but possible.

Who knows. Maybe someone could write a translator from an OO
language like C++ into pure C! Do you think that's possible?

--
Chris "Cleft? Cright? Cback? Cside? I do like to be ..." Dollin
Nit-picking is best done among friends.

Nov 15 '06 #5

P: n/a

"Thierry Chappuis" <th*****@mujigka.chwrote in message
news:11*********************@i42g2000cwa.googlegro ups.com...
Hi,

I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. I'm studying the GObject library and Laurent
Deniau's OOPC framework published on his web site at
http://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html. The approach is
very instructive. I know that I could do much of this stuff with e.g.
C++, but the intellectual challenge of implementing these concepts with
pure ANSI C is relevant to me.

Are you aware of another approaches? Any experience in using such
techniques in production code? The use of GObject seems to be well
implemented in the GNOME world, but I didn't find much about Laurent
Deniau's OOPC. Have you some comments about the strengths and drawbacks
of such techniques?

Many thanks for your valuable help and comments

Best regards

Thierry
Look at the way a Widget is defined in the Unix Xt or Motif libraries.
--
Fred L. Kleinschmidt
Boeing Associate Technical Fellow
Technical Architect, Software Reuse Project
Nov 15 '06 #6

P: n/a
Chris Dollin wrote:
Cong Wang wrote:
Yeah. This is an interesting topic. In fact, C can NOT fully support
OOP like C++,
<snip>
Who knows. Maybe someone could write a translator from an OO
language like C++ into pure C! Do you think that's possible?
Didn't very early versions of g++ do that?

Nov 15 '06 #7

P: n/a
In article <11*********************@i42g2000cwa.googlegroups. com>,
<ra*****@gmail.comwrote:
>That's just one of the three requirements for an OO programming
language, encapsulation. The other two are inheritance and
polymorphism
Requirements? Common characteristics perhaps.
>struct Parent
{
int a,b;
};

struct Child
{
int a,b;
more variables
};
>
struct Child2
{
int a,b;
more variables
}

If you want to pass a Child or a Child2 to a function, instead of
making two version of the function (which need different names because
there is no overloading in C), you can make the function take a Parent,
and then pass a Child or a Child2 'c' by saying (Parent)c. I'm not
sure if this just happens to work, or if it is actually defined in the
C standard that the variables of a structure appear in memory in the
order that they are specified in the declaration.
The structure specifies that given a union of two struct types with
common initial sequences, you can access that common part through
either of the union members. Since given independent compilation it
is often impossible to be certain whether a structure is in a union
with another suitable type, in practice this is guaranteed to work.
>I haven't seen any way to do polymorphism.
Structures containing pointers to functions. For example, give every
type that can draw itself a member void (*draw)(Type obj, Screen screen),
and call obj->draw(obj, screen). Not very elegant, but you can define
a wrapper.

-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.
Nov 15 '06 #8

P: n/a
In article <ej**********@pc-news.cogsci.ed.ac.uk>, I wrote:
>The structure specifies that given a union of two struct types with
^^^^^^^^^

This should have read "standard" of course.

-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.
Nov 15 '06 #9

P: n/a
"santosh" <sa*********@gmail.comwrites:
Chris Dollin wrote:
Cong Wang wrote:
Yeah. This is an interesting topic. In fact, C can NOT fully support
OOP like C++,
<snip>
Who knows. Maybe someone could write a translator from an OO
language like C++ into pure C! Do you think that's possible?
At the very worse, one would code in C an emulator for a x86 and then run
the emulator on the generated X86 code which would be a very large constant
for the program. Obviously C can be coded at such a low level than there
are better approaches.

BTW, C code is quite common as a target langage for early compilers of new
langages.
Didn't very early versions of g++ do that?
Not that I know of. CFront did that. Comeau still do it. I think EDG
provides an example back end for its front end which does it.

That's not very different that doing a compiler. What would be more
problematic is doing such a compiler which produce mainable C code.

Yours,

--
Jean-Marc
Nov 15 '06 #10

P: n/a
I haven't seen any way to do polymorphism. I guess that's kind of like
templates in C++, although templates are technically not polymorphism,
they are a hack to acheive the effect of polymorphism. This is because
the templates are handled at compile time, and true OO polymorphism is
runtime polymorphism.
It is quite easy to implement something like polymorphism using
function pointers (very simplified):

struct Parent {
int data;
void (*print)(void);
};

struct Child {
int data;
void(*print)(void);
int data2;
int (*getData2)(void);
};

In the code above, function pointers can be mapped to specialized
fonctions at object creation time. However, data alignment is matter of
concern, especially when complicated inheritance shemes or multiple
inheritance are involved. It seems to be more common practice to group
all function pointers in a separate structure called virtual table
(from C++ terminology):

struct Parent {
struct Parent_virtual_table *_vptr; /* pointer to a structure
containing function pointers*/
int data_parent;
}

The above-mentioned Laurent Deniau's web site present a quite usable
object model that implements both simple and multiple inheritance, and
virtual (object functions) and non-virtual functions (class functions),
based on the C++ object model. I'm still studying the limits of the
model proposed and I'm interested in all suggestions and experiences in
this field.

I'm interested in earing from the experience of some of use about the
use of some OO-like constructs in moderately large C ANSI projects. It
sees not too complicated to design basic OO stuffs usable for
small/medium-size projects.

Moreover, coming from the linux world, I'm still looking inside the
gobject model and try to gain some experience with it. Your comments
are wellcome!

I know that I can do OOP much more easily using C++, but implementing
its concepts in pure ANSI C makes me more aware of the underlying
mechanisms, and helps me to organsize my C code in more modular way.

Thierry

Nov 15 '06 #11

P: n/a

Chris Dollin wrote:
Cong Wang wrote:
Yeah. This is an interesting topic. In fact, C can NOT fully support
OOP like C++,

It doesn't have syntactic support -- and that makes writing OO
code a real bigger -- but you can do polymorphism/inheritance
if you must; I think there's just enough room in the Standard
to make the required machinery legal.

Painful, but possible.

Who knows. Maybe someone could write a translator from an OO
language like C++ into pure C! Do you think that's possible?
I think you would call it a compiler. You might even call
it
--
Chris "Cleft? Cright? Cback? Cside? I do like to be ..." Dollin
Nit-picking is best done among friends.
Nov 15 '06 #12

P: n/a
On Nov 15, 11:31 am, rich...@cogsci.ed.ac.uk (Richard Tobin) wrote:
In article <1163605918.137964.21...@i42g2000cwa.googlegroups. com>,

<raza...@gmail.comwrote:
That's just one of the three requirements for an OO programming
language, encapsulation. The other two are inheritance and
polymorphismRequirements? Common characteristics perhaps.

I guess 'requirements' was a strong word. The programming language
textbooks I've seen all list those three as necessary for OO languages.
The line between OO and iterative languages is much fuzzier than
between (I don't remember the exact terms) iterative, functional (e.g.
Lisp) and logical (e.g. Prolog).

Colin K.

Nov 15 '06 #13

P: n/a

"Thierry Chappuis" <th*****@mujigka.chwrote in message news
Hi,

I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. I'm studying the GObject library and Laurent
Deniau's OOPC framework published on his web site at
http://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html. The approach is
very instructive. I know that I could do much of this stuff with e.g.
C++, but the intellectual challenge of implementing these concepts with
pure ANSI C is relevant to me.

Are you aware of another approaches? Any experience in using such
techniques in production code? The use of GObject seems to be well
implemented in the GNOME world, but I didn't find much about Laurent
Deniau's OOPC. Have you some comments about the strengths and drawbacks
of such techniques?
I've got a system in place where "objects" implement "interfaces". So you
say

PORTABLE *port = isa(object, "portable");

if the function returns a pointer, object is portable, and has "weight",
"carry", "drop" and similar methods, accessible throught he function
pointer.

This is terribly inefficient, but it is game logic for an adventure game, so
the program has a tenth of a second or so to respond, which is ample for a
few string manipulations.
--
www.personal.leeds.ac.uk/~bgy1mm
freeware games to download.
Nov 15 '06 #14

P: n/a
ra*****@gmail.com writes:
On Nov 15, 11:31 am, rich...@cogsci.ed.ac.uk (Richard Tobin) wrote:
>In article <1163605918.137964.21...@i42g2000cwa.googlegroups. com>,

<raza...@gmail.comwrote:
>That's just one of the three requirements for an OO programming
language, encapsulation. The other two are inheritance and
polymorphismRequirements? Common characteristics perhaps.

I guess 'requirements' was a strong word. The programming language
textbooks I've seen all list those three as necessary for OO languages.
The line between OO and iterative languages is much fuzzier than
between (I don't remember the exact terms) iterative, functional (e.g.
Lisp) and logical (e.g. Prolog).

Colin K.
I think you mean "procedural" rather than "iterative".

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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.
Nov 15 '06 #15

P: n/a
Chris Dollin wrote:
Cong Wang wrote:
>Yeah. This is an interesting topic. In fact, C can NOT fully
support OOP like C++,

It doesn't have syntactic support -- and that makes writing OO
code a real bigger -- but you can do polymorphism/inheritance
if you must; I think there's just enough room in the Standard
to make the required machinery legal.

Painful, but possible.

Who knows. Maybe someone could write a translator from an OO
language like C++ into pure C! Do you think that's possible?
That is how earlier C++ systems were implemented. Look up Cfront.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>

Nov 16 '06 #16

P: n/a
CBFalconer <cb********@yahoo.comwrites:
Chris Dollin wrote:
>Cong Wang wrote:
>>Yeah. This is an interesting topic. In fact, C can NOT fully
support OOP like C++,

It doesn't have syntactic support -- and that makes writing OO
code a real bigger -- but you can do polymorphism/inheritance
if you must; I think there's just enough room in the Standard
to make the required machinery legal.

Painful, but possible.

Who knows. Maybe someone could write a translator from an OO
language like C++ into pure C! Do you think that's possible?

That is how earlier C++ systems were implemented. Look up Cfront.
Yeah, I think Chris knows that, as he strongly hinted in his signature:

| Chris "Cleft? Cright? Cback? Cside? I do like to be ..." Dollin

(Sorry if I'm spoiling the joke.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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.
Nov 16 '06 #17

P: n/a
In article <11**********************@f16g2000cwb.googlegroups .com>
Thierry Chappuis <th*****@mujigka.chwrote, in part:
>struct Parent {
int data;
void (*print)(void);
};

struct Child {
int data;
void(*print)(void);
int data2;
int (*getData2)(void);
};
I prefer to embed the "parent" structure into the "child":

struct Child {
struct Parent parent;
int data2;
int (*getData2)(void);
};

in this case. Going from child to parent is easy and cast-free:

struct Child *cp;
...
operate_on_parent(&cp->parent);

although going the other way (parent back to "known" child)
requires either a cast, or a trip through "void *".

(It might be nice if C99 had adopted (or perhaps C0X could adopt)
the Plan 9 extensions that make this work more cleanly.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 16 '06 #18

P: n/a
Keith Thompson wrote:
ra*****@gmail.com writes:
>On Nov 15, 11:31 am, rich...@cogsci.ed.ac.uk (Richard Tobin) wrote:
>>In article <1163605918.137964.21...@i42g2000cwa.googlegroups. com>,

<raza...@gmail.comwrote:
That's just one of the three requirements for an OO programming
language, encapsulation. The other two are inheritance and
polymorphismRequirements? Common characteristics perhaps.

I guess 'requirements' was a strong word. The programming language
textbooks I've seen all list those three as necessary for OO languages.
The line between OO and iterative languages is much fuzzier than
between (I don't remember the exact terms) iterative, functional (e.g.
Lisp) and logical (e.g. Prolog).

Colin K.

I think you mean "procedural" rather than "iterative".
"imperative". Commands that change things. OO languages are, of
course, typically imperative. It's not a yes/no, there's more
of a range - Lisp is imperative, in that it /has/ state and changes
thereunto, but a lot of the language is to do with the functional
(as in having & using functions) part, so it supports a functional
style. A notable feature of the pure functional languages is that
they have /no/ state (and so no changes to it), which makes gluing
them into the imperative world interesting.

--
Chris "hantwig efferko VOOM!" Dollin
"Life is full of mysteries. Consider this one of them." Sinclair, /Babylon 5/

Nov 16 '06 #19

P: n/a
CBFalconer wrote:
Chris Dollin wrote:
>Who knows. Maybe someone could write a translator from an OO
language like C++ into pure C! Do you think that's possible?

That is how earlier C++ systems were implemented. Look up Cfront.
(fx:smirk)

--
Chris "bonus points to Keith Thompson" Dollin
The shortcuts are all full of people using them.

Nov 16 '06 #20

P: n/a
On 15 Nov 2006 02:28:02 -0800, "Thierry Chappuis" wrote:
>I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. I'm studying the GObject library and Laurent
Deniau's OOPC framework published on his web site at
http://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html.
I bookmarked that link some time ago as an example how it should _not_
be done.
>The approach is
very instructive. I know that I could do much of this stuff with e.g.
C++, but the intellectual challenge of implementing these concepts with
pure ANSI C is relevant to me.

Are you aware of another approaches? Any experience in using such
techniques in production code?
Many approaches use function pointers or hand-written vtables to
emulate polymorphism. But, AFAIK, they all hide the implementation
under a bunch of preprocessor macros to make it appear more 'object
oriented'. Essentially they create their own OO-language based on
macros which might be 'instructive' but also is rather uninviting for
most real world developers. See e.g.

http://www.ddj.com/184406396
http://www.pvv.ntnu.no/~hakonhal/main.cgi/c/classes
http://www.embedded.com/97/fe29712.htm

You find many links when you search for 'object-oriented programming
in C'.

Best wishes,
Roland Pibinger
Nov 16 '06 #21

P: n/a

Roland Pibinger a écrit :
Many approaches use function pointers or hand-written vtables to
emulate polymorphism. But, AFAIK, they all hide the implementation
under a bunch of preprocessor macros to make it appear more 'object
oriented'. Essentially they create their own OO-language based on
macros which might be 'instructive' but also is rather uninviting for
most real world developers. See e.g.
Even with hand-written vtables, it is not a requirement to hide
implementation under macros and the resulting code does not seem to
heavy to handle and maintain. Do you think emulating inheritance and
polymorphism in this way is bad C practice?
http://www.ddj.com/184406396
http://www.pvv.ntnu.no/~hakonhal/main.cgi/c/classes
http://www.embedded.com/97/fe29712.htm
Many thanks for the links. I'll study these differents approaches.

Best reagards

Thierry

Nov 16 '06 #22

P: n/a
CBFalconer wrote:
Chris Dollin wrote:
Who knows. Maybe someone could write a translator from an OO
language like C++ into pure C! Do you think that's possible?

That is how earlier C++ systems were implemented. Look up Cfront.

I think, but wouldn't swear to it, that Comeau can provide a C++
compiler that produces C code.


Brian
Nov 16 '06 #23

P: n/a
On 16 Nov 2006 09:07:04 -0800, "Thierry Chappuis" wrote:
>Even with hand-written vtables, it is not a requirement to hide
implementation under macros and the resulting code does not seem to
heavy to handle and maintain. Do you think emulating inheritance and
polymorphism in this way is bad C practice?
Not necessarily. Usability, as always, is the criterion. A solution
that avoids e.g. macros, void* parameters and casts required from
users has a higher probability of being accepted.

Best wishes,
Roland Pibinger
Nov 16 '06 #24

P: n/a

Roland Pibinger a écrit :
On 16 Nov 2006 09:07:04 -0800, "Thierry Chappuis" wrote:
Even with hand-written vtables, it is not a requirement to hide
implementation under macros and the resulting code does not seem to
heavy to handle and maintain. Do you think emulating inheritance and
polymorphism in this way is bad C practice?

Not necessarily. Usability, as always, is the criterion. A solution
that avoids e.g. macros, void* parameters and casts required from
users has a higher probability of being accepted.

Best wishes,
Roland Pibinger
Thank you for your valuable input.

Best wishes

Thierry

Nov 16 '06 #25

P: n/a
Roland Pibinger wrote:
On 16 Nov 2006 09:07:04 -0800, "Thierry Chappuis" wrote:
>>Even with hand-written vtables, it is not a requirement to hide
implementation under macros and the resulting code does not seem to
heavy to handle and maintain. Do you think emulating inheritance and
polymorphism in this way is bad C practice?


Not necessarily. Usability, as always, is the criterion. A solution
that avoids e.g. macros
Why do you think that macros should be avoided?
void* parameters and casts required from
users has a higher probability of being accepted.
Agreed.

a+, ld.
Nov 17 '06 #26

P: n/a
On Fri, 17 Nov 2006 12:55:36 +0100, Laurent Deniau wrote:
>Roland Pibinger wrote:
>On 16 Nov 2006 09:07:04 -0800, "Thierry Chappuis" wrote:
>>>Even with hand-written vtables, it is not a requirement to hide
implementation under macros and the resulting code does not seem to
heavy to handle and maintain. Do you think emulating inheritance and
polymorphism in this way is bad C practice?

Not necessarily. Usability, as always, is the criterion. A solution
that avoids e.g. macros

Why do you think that macros should be avoided?
Macros usually obfuscate code more than clarify it. They make code
difficult to understand and write. Also error messages become harder
to decrypt. The following example hardly resembles procedural C code
any more:

#undef OBJECT
#define OBJECT person

BASEOBJECT_INTERFACE

char const* private(name);

BASEOBJECT_METHODS

void constMethod(print);

ENDOF_INTERFACE

CLASS_INTERFACE

t_person *const classMethod_(new) char const name[] __;
void method_(init) char const name[] __;
void method_(copy) t_person const*const per __;

ENDOF_INTERFACE

I expect from C code that it uses common C styles and idioms. IMO,
heavy use of the preprocessor is a means to avoid C programming.

Best regards,
Roland Pibinger
Nov 17 '06 #27

P: n/a

Roland Pibinger a écrit :
On Fri, 17 Nov 2006 12:55:36 +0100, Laurent Deniau wrote:
Roland Pibinger wrote:
On 16 Nov 2006 09:07:04 -0800, "Thierry Chappuis" wrote:
Even with hand-written vtables, it is not a requirement to hide
implementation under macros and the resulting code does not seem to
heavy to handle and maintain. Do you think emulating inheritance and
polymorphism in this way is bad C practice?

Not necessarily. Usability, as always, is the criterion. A solution
that avoids e.g. macros
Why do you think that macros should be avoided?

Macros usually obfuscate code more than clarify it. They make code
difficult to understand and write. Also error messages become harder
to decrypt. The following example hardly resembles procedural C code
any more:

#undef OBJECT
#define OBJECT person

BASEOBJECT_INTERFACE

char const* private(name);

BASEOBJECT_METHODS

void constMethod(print);

ENDOF_INTERFACE

CLASS_INTERFACE

t_person *const classMethod_(new) char const name[] __;
void method_(init) char const name[] __;
void method_(copy) t_person const*const per __;

ENDOF_INTERFACE

I expect from C code that it uses common C styles and idioms. IMO,
heavy use of the preprocessor is a means to avoid C programming.
I cannot agree with your point of view. In the above-mentioned example,
macros only hide the implementation of the object system. Such
low-level details are probably irrelevant to the user.

All the logic of the a program is implemented in standardized C code.
How about the use the presented person abstraction:

t_person *const per = person.new("Thierry");
sendMsg(per, print);
delete(per);

or
t_person *const per = person.new("Thierry");
per->__vptr->print(per);
delete(per);

For me it is C code: t_person is a structure or an union (in the
present case) and new points to a function responsible to create the
object. You can easily avoid the use of the macro sendMsg to call the
function print if you have some knowledge of the implementation (the
essentiel of the model can be understood from ooc.h). And you use
delete as you would use a wrapper free. What is not C in this code?

Thierry

Best regards,
Roland Pibinger
Nov 17 '06 #28

P: n/a
Roland Pibinger wrote:
On Fri, 17 Nov 2006 12:55:36 +0100, Laurent Deniau wrote:
>>Roland Pibinger wrote:
>>>On 16 Nov 2006 09:07:04 -0800, "Thierry Chappuis" wrote:

Even with hand-written vtables, it is not a requirement to hide
implementation under macros and the resulting code does not seem to
heavy to handle and maintain. Do you think emulating inheritance and
polymorphism in this way is bad C practice?

Not necessarily. Usability, as always, is the criterion. A solution
that avoids e.g. macros

Why do you think that macros should be avoided?


Macros usually obfuscate code more than clarify it. They make code
difficult to understand and write. Also error messages become harder
to decrypt. The following example hardly resembles procedural C code
any more:

#undef OBJECT
#define OBJECT person

BASEOBJECT_INTERFACE

char const* private(name);

BASEOBJECT_METHODS

void constMethod(print);

ENDOF_INTERFACE

CLASS_INTERFACE

t_person *const classMethod_(new) char const name[] __;
void method_(init) char const name[] __;
void method_(copy) t_person const*const per __;

ENDOF_INTERFACE

I expect from C code that it uses common C styles and idioms. IMO,
heavy use of the preprocessor is a means to avoid C programming.
I partially agree. I have often said here or on fr.c.l.c that OOPC was
more a didactic paper to explain some facettes of C++. I have never used
it nor recommended to use it for professionnal developement.

After OOPC I developped during my free time, 3 other frameworks to do OO
in C (OOC-1.0, OOC-2.0 and COS = C Object System). I will not go into
the details and the history of this evolution over the past 6 years (if
you read french, you may have a look on many threads on this topic on
fr.c.l.c).

About the usage of the macros, and if you have a small knowledge of CLOS
and Objective-C syntax, what do you think of following working (but
incomplete) C99 code which uses COS macros to defines generics, class
and multimethods as generics specialisations, does it looks so different
from what we find in OO langages?

// sample of Generic.h
defgeneric(OBJ, gGetAt , (Container, Position));
defgeneric(OBJ, gGetAtIdx, (Container, (int)idx);
defgeneric(OBJ, gPutAt , (Container, Object, Position));
defgeneric(OBJ, gPutAtIdx, (Container, Object), (int)idx);

// sample of Generic.c
makgeneric(OBJ, gGetAt , (Container, Position));
makgeneric(OBJ, gPutAt , (Container, Object, Position));
makgeneric(OBJ, gPutAtIdx, (Container, Object), (int)idx);

// sample of Array.h
#include <cos/Collection.h>

defclass(Array, Collection)
int len;
OBJ *data;
endclass

// sample of Array.c
#include <cos/Array.h>

makclass(Array, Collection);

defmethod(OBJ, gPutAtIdx, (Array, Object), (int)idx)
{
if (0 idx && idx >= self1->len) {
useclass(ExOutOfBound);
gThrow(gNewWithStr(ExOutOfBound, "invalid array index"));
}

if (self1->data[idx] != self2) {
if (self1->data[idx] != NIL)
gRelease(self1->data[idx]);

self1->data[idx] = gRetain(self2);
}

retmethod(self1);
}

// sample of main.c
#include <stdio.h>
#include <cos/cos.h>

useclass(Array,Integer,ExOutOfBound);

int main(void)
{
TRY
OBJ array = gNewWithSize(Array, 100);
OBJ value = gNewWithInt(Integer, 10);

gPutAtIdx(array, value, 15); // OK
gPutAtIdx(array, value, 200); // throw ExOutOfBound

CATCH(ExOutOfBound, ex)
fprintf(stderr, "exception %s thrown (%s,%i) and caught (%s,%i):"
"%s\n",
gNameStr(ex), ex_file, ex_line, __FILE__, __LINE__,
gReasonStr(ex));

FINALLY(ex)
gRelease(ex);
gRelease(array);
gRelease(value);
ENDTRY;
}

Note that generics are C functions (you can take a pointer to them) and
I use the convention (it's only a convention, not a requirement) to call
them gGeneric or vGeneric (variadic) to mark the difference of their
role with C functions.

a+, ld.
Nov 17 '06 #29

P: n/a
Laurent Deniau wrote:
>
defmethod(OBJ, gPutAtIdx, (Array, Object), (int)idx)
{
if (0 idx && idx >= self1->len) {
useclass(ExOutOfBound);
gThrow(gNewWithStr(ExOutOfBound, "invalid array index"));
}

if (self1->data[idx] != self2) {
if (self1->data[idx] != NIL)
gRelease(self1->data[idx]);

self1->data[idx] = gRetain(self2);
}

retmethod(self1);
}
Sorry this closing brace must be replaced by 'endmethod' and its
corresponding openning brace must be removed.

a+, ld.
Nov 17 '06 #30

P: n/a
Thierry Chappuis wrote:
I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. I'm studying the GObject library and Laurent
Deniau's OOPC framework published on his web site at
http://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html. The approach is
very instructive. I know that I could do much of this stuff with e.g.
C++, but the intellectual challenge of implementing these concepts with
pure ANSI C is relevant to me.

Are you aware of another approaches? Any experience in using such
techniques in production code? The use of GObject seems to be well
implemented in the GNOME world, but I didn't find much about Laurent
Deniau's OOPC. Have you some comments about the strengths and drawbacks
of such techniques?
Please find attached a C implementation
of Bjarne Stroustrup's famous Shape class.

C is not an object oriented programming language
but you can write object oriented programs in C
including programs that implement run-time polymorphism.
The fprintf function on type *FILE is an example.
You don't need a language translator or a special library.

A program is not an object oriented programming language
just because it is written in an object oriented programming language.
All the popular object oriented programming languages are
procedural programming languages first.
An object oriented program must actually use
the object oriented features of the language.
Object oriented programming is first of all a programming style.

The problem with C is that it does not directly support features
such as inheritance and run-time polymorphism. Good C programmers
have always used an object oriented programming style
but implementing object oriented programs in C is problematic --
tedious and error prone. The C++ programming language provides
direct support for object oriented programming
so it is much easier and more reliable.
cat Point.h
#ifndef GUARD_Point_h
#define GUARD_Point_h 1

typedef struct Point {
// representation
double X;
double Y;
} Point;
// functions
double
Point_x(const Point* p);
double
Point_y(const Point* p);
Point*
Point_initialize(Point* p, double x, double y);
// constructors
Point
Point_createExplicit(double x, double y);
Point
Point_createDefault(void);
Point*
Point_newExplicit(double x, double y);
Point*
Point_newDefault(void);
// destructors
void
Point_destroy(const Point* p);
void
Point_delete(const Point* p);

#endif // GUARD_Point_h
cat Point.c
// gcc -Wall -std=c99 -pedantic -I. -O2 -c Point.c

#include<Point.h>
#include<stdlib.h>

// functions
double
Point_x(const Point* p) {
return p->X; }
double
Point_y(const Point* p) {
return p->Y; }
Point*
Point_initialize(Point* p, double x, double y) {
p->X = x;
p->Y = y;
return p;
}
// constructors
Point
Point_createExplicit(double x, double y) {
Point p;
Point_initialize(&p, x, y);
return p;
}
Point
Point_createDefault(void) {
return Point_createExplicit(0.0, 0.0); }
Point*
Point_newExplicit(double x, double y) {
Point* p = (Point*)malloc(sizeof(Point));
Point_initialize(p, x, y);
return p; }
Point*
Point_newDefault(void) {
return Point_newExplicit(0.0, 0.0); }
// destructors
void
Point_destroy(const Point* p) { }
void
Point_delete(const Point* p) {
Point_destroy(p);
free((void*)p); }
cat Color.h
#ifndef GUARD_Color_h
#define GUARD_Color_h 1
typedef struct Color {
// representation
unsigned int R; // red
unsigned int G; // green
unsigned int B; // blue
} Color;
// functions
unsigned int
Color_red(const Color *c);
unsigned int
Color_green(const Color *c);
unsigned int
Color_blue(const Color *c);
Color*
Color_initialize(Color* c,
unsigned int r,
unsigned int g,
unsigned int b);
// constructors
Color
Color_createExplicit(
unsigned int r,
unsigned int g,
unsigned int b);
Color
Color_createDefault(void);
Color*
Color_newExplicit(
unsigned int r,
unsigned int g,
unsigned int b);
Color*
Color_newDefault(void);
// destructor
void
Color_destroy(const Color *c);
void
Color_delete(const Color *c);

#endif // GUARD_Color_h
cat Color.c
// gcc -Wall -std=c99 -pedantic -I. -O2 -c Color.c

#include<Color.h>
#include<stdlib.h>

// functions
unsigned int
Color_red(const Color *c) {
return c->R; }
unsigned int
Color_green(const Color *c) {
return c->G; }
unsigned int
Color_blue(const Color *c) {
return c->B; }
Color*
Color_initialize(Color* c,
unsigned int r,
unsigned int g,
unsigned int b) {
c->R = r;
c->G = g;
c->B = b;
return c;
}
// constructors
Color
Color_createExplicit(
unsigned int r,
unsigned int g,
unsigned int b) {
Color c;
Color_initialize(&c, r, g, b);
return c; }
Color
Color_createDefault(void) {
return Color_createExplicit(0, 0, 0); }
Color*
Color_newExplicit(
unsigned int r,
unsigned int g,
unsigned int b) {
Color* c = (Color*)malloc(sizeof(Color));
Color_initialize(c, r, g, b);
return c; }
Color*
Color_newDefault(void) {
return Color_newExplicit(0, 0, 0); }
// destructors
void
Color_destroy(const Color *c) { }
void
Color_delete(const Color *c) {
Color_destroy(c);
free((void*)c); }
cat Shape.h
#ifndef GUARD_Shape_h
#define GUARD_Shape_h 1

#include<Point.h>
#include<Color.h>

typedef struct Shape {
// representation
const
void* V; // virtual function table pointer
Point P;
Color C;
} Shape;
// functions
const Point*
Shape_point(const Shape* s);
const Color*
Shape_color(const Shape* s);
void
actualShape_draw(const Shape* s);
double
actualShape_area(const Shape* s);
void
Shape_draw(const Shape* s); // virtual function
double
Shape_area(const Shape* s); // virtual function
Shape*
Shape_initialize(Shape* s,
const void* v,
const Point* p,
const Color* c);
// constructors
Shape
Shape_createExplicit(
const Point* p,
const Color* c);
Shape
Shape_createDefault(void);
Shape*
Shape_newExplicit(
const Point* p,
const Color* c);
Shape*
Shape_newDefault(void);
// destructors
void
Shape_destroy(const Shape* s);
void
Shape_delete(const Shape* s);

#endif // GUARD_Shape_h
cat Shape.c
// gcc -Wall -std=c99 -pedantic -I. -O2 -c Shape.c

#include<stdio.h>
#include<Shape.h>
#include<stdlib.h>

// functions
const Point*
Shape_point(const Shape* s) {
return &(s->P); }
const Color*
Shape_color(const Shape* s) {
return &(s->C); }
void
actualShape_draw(const Shape* s) {
fprintf(stderr, "Shape_draw(const Shape*)\n");
fflush(stderr); }
double
actualShape_area(const Shape* s) {
fprintf(stderr, "Shape_area(const Shape*)\n");
fflush(stderr);
return 0.0; }

typedef struct Shape_vtable_t {
void (*Shape_draw)(const Shape*);
double (*Shape_area)(const Shape*);
} Shape_vtable_t;
static const
Shape_vtable_t
Shape_vtable = {actualShape_draw, actualShape_area};

void
Shape_draw(const Shape* s) { // virtual function
((Shape_vtable_t*)(s->V))->Shape_draw(s); }
double
Shape_area(const Shape* s) { // virtual function
return ((Shape_vtable_t*)(s->V))->Shape_area(s); }
Shape*
Shape_initialize(Shape* s,
const
void* v,
const
Point* p,
const
Color* c) {
s->V = v;
Point_initialize(&(s->P), Point_x(p), Point_y(p));
Color_initialize(&(s->C), Color_red(c), Color_green(c), Color_blue(c));
return s; }
// constructors
Shape
Shape_createExplicitShape(
const Point* p,
const Color* c) {
Shape s;
Shape_initialize(&s, (const void*)(&Shape_vtable), p, c);
return s; }
Shape
Shape_createDefault(void) {
Shape s;
Point p = Point_createDefault();
Color c = Color_createDefault();
Shape_initialize(&s, (const void*)(&Shape_vtable), &p, &c);
Color_destroy(&c);
Point_destroy(&p);
return s; }
Shape*
Shape_newExplicitShape(
const Point* p,
const Color* c) {
Shape* s = (Shape*)malloc(sizeof(Shape));
Shape_initialize(s, (const void*)(&Shape_vtable), p, c);
return s; }
Shape*
Shape_newDefault(void) {
Shape* s = (Shape*)malloc(sizeof(Shape));
Point p = Point_createDefault();
Color c = Color_createDefault();
Shape_initialize(s, (const void*)(&Shape_vtable), &p, &c);
Color_destroy(&c);
Point_destroy(&p);
return s; }
// destructors
void
Shape_destroy(const Shape* s) {
Color_destroy(Shape_color(s));
Point_destroy(Shape_point(s));
}
void
Shape_delete(const Shape* s) {
Shape_destroy(s);
free((void*)s); }
cat Circle.h
#ifndef GUARD_Circle_h
#define GUARD_Circle_h 1

#include<Shape.h>

typedef struct Circle {
Shape S; // public base class
double R; // radius
} Circle;
// functions
const Shape*
Circle_shape(const Circle* c);
double
Circle_radius(const Circle* c);
void
actualCircle_draw(const Circle* c);
double
actualCircle_area(const Circle* c);
void
Circle_draw(const Circle* c); // virtual function
double
Circle_area(const Circle* c); // virtual function
Circle*
Circle_initialize(Circle* c, const Shape* s, double r);
// constructors
Circle
Circle_createDefault(void);
Circle
Circle_createExplicit(const Shape* s, double r);
Circle*
Circle_newDefault(void);
Circle*
Circle_newExplicit(const Shape* s, double r);
// destructors
void
Circle_destroy(const Circle* c);
void
Circle_delete(const Circle* c);

#endif // GUARD_Circle_h
cat Circle.c
// gcc -Wall -std=c99 -pedantic -I. -O2 -c Circle.c

#include<math.h>
#include<stdio.h>
#include<Circle.h>
#include<stdlib.h>

// functions
const Shape*
Circle_shape(const Circle* c) {
return &(c->S); }
double
Circle_radius(const Circle* c) {
return c->R; }
void
actualCircle_draw(const Circle* c) {
fprintf(stderr, "Circle_draw(const Circle*)\n");
fflush(stderr); }
double
actualCircle_area(const Circle* c) {
const
double pi = 3.14159265358979323846;
const
double r = Circle_radius(c);
fprintf(stderr, "Circle_area(const Circle*)\n");
fflush(stderr);
return pi*r*r; }

typedef struct Circle_vtable_t {
void (*Circle_draw)(const Circle*);
double (*Circle_area)(const Circle*);
} Circle_vtable_t;
static const
Circle_vtable_t
Circle_vtable = {actualCircle_draw, actualCircle_area};
void
Circle_draw(const Circle* c) { // virtual function
((Circle_vtable_t*)(c->S.V))->Circle_draw(c);
}
double
Circle_area(const Circle* c) { // virtual function
return ((Circle_vtable_t*)(c->S.V))->Circle_area(c);
}

Circle*
Circle_initialize(Circle* c, const Shape* s, double r) {
Shape_initialize(&(c->S),
(void*)(&Circle_vtable),
Shape_point(s),
Shape_color(s));
c->R = r;
return c; }

// constructors
Circle
Circle_createExplicit(const Shape* s, double r) {
Circle c;
Circle_initialize(&c, s, r);
return c; }
Circle
Circle_createDefault(void) {
Circle c;
const
Shape s = Shape_createDefault();
Circle_initialize(&c, &s, 0.0);
Shape_destroy(&s);
return c; }
Circle*
Circle_newExplicit(const Shape* s, double r) {
Circle* c = (Circle*)malloc(sizeof(Circle));
Circle_initialize(c, s, r);
return c; }
Circle*
Circle_newDefault(void) {
Circle* c = (Circle*)malloc(sizeof(Circle));
const
Shape s = Shape_createDefault();
Circle_initialize(c, &s, 0.0);
Shape_destroy(&s);
return c; }
// destructors
void
Circle_destroy(const Circle* c) {
Shape_destroy(Circle_shape(c));
}
void
Circle_delete(const Circle* c) {
Shape_destroy(Circle_shape(c));
free((void*)c); }
cat main.c
// gcc -Wall -std=c99 -pedantic -I. -O2 -o main main.c Circle.o Shape.o Color.o Point.o

#include<stdio.h>
#include<Circle.h>

int
main(int argc, char* argv[]) {
const
Shape s = Shape_createDefault();
const
Circle c = Circle_createExplicit(&s, 2.0);
Shape_draw((const Shape*)(&c));
fprintf(stdout, "%g = radius\t %g = area\n",
Circle_radius(&c), Shape_area((const Shape*)(&c)));
return 0;
}
cat Makefile
CC=gcc
DEFINES=
INCLUDE=-I.
OPTIONS=-Wall -std=c99 -pedantic -O2
LIBRARY=
OBJECTS=Point.o Color.o Shape.o Circle.o
SOURCES=Point.c Color.c Shape.c Circle.c
HEADERS=Point.h Color.h Shape.h Circle.h
library=
COMPILE=$(CC) $(DEFINES) $(INCLUDE) $(LIBRARY) $(OPTIONS)

main: $(HEADERS) $(OBJECTS) main.c
$(COMPILE) -o main main.c $(OBJECTS) $(library)

Point.o: Point.h Point.c
$(COMPILE) -c Point.c

Color.o: Color.h Color.c
$(COMPILE) -c Color.c

Shape.o: Shape.h Shape.c
$(COMPILE) -c Shape.c

Circle.o: Circle.h Circle.c
$(COMPILE) -c Circle.c

clean:
rm -f main $(OBJECTS)

Nov 17 '06 #31

P: n/a
On Fri, 17 Nov 2006 10:53:58 -0800, "E. Robert Tisdale" wrote:
>Thierry Chappuis wrote:
>I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. of such techniques?

Please find attached a C implementation
of Bjarne Stroustrup's famous Shape class.
Your approach is similar to the results of my experiments with OO in
C. You can increase encapsulation when you only forward declare your
structs (e.g. struct Shape) in the header files. Also some functions
(e.g. actualShape_draw) can be removed form the header and made
'private', i.e. static, in the respecive *.c file.

Best regards,
Roland Pibinger
Nov 17 '06 #32

P: n/a
There's a book/paper called "Object-Oriented Programming with ANSI-C"
by Axel-Tobias Schreiner, available as a PDF at
http://www.planetpdf.com/codecuts/pdfs/ooc.pdf. It explores this area
to a great extend and I'd really recommend it.

--
WYCIWYG - what you C is what you get

Nov 17 '06 #33

P: n/a
On 17 Nov 2006 12:40:34 -0800, "matevzb" <ma*****@gmail.comwrote:
>There's a book/paper called "Object-Oriented Programming with ANSI-C"
by Axel-Tobias Schreiner, available as a PDF at
http://www.planetpdf.com/codecuts/pdfs/ooc.pdf. It explores this area
to a great extend and I'd really recommend it.
It's awful! IIRC, it needs AWK as preprocessor and uses mostly untyped
void* pointers. IIRC, the book was never published in English because
it found no publisher. Guess why.

Regards,
Roland Pibinger
Nov 17 '06 #34

P: n/a
It's awful! IIRC, it needs AWK as preprocessor and uses mostly untyped
void* pointers.
That was just my opinion and you don't have to agree. I found it
useful, as it demonstrates what can be done in C. Void pointers can be
dangerous, but then again, what would C be without them? =)
(AWK is optional, depending on what you want to do)
IIRC, the book was never published in English because
it found no publisher. Guess why.
Many books haven't been published in English. That doesn't mean they're
bad books. (same goes for the authors)

--
WYCIWYG - what you C is what you get

Nov 17 '06 #35

P: n/a
"Thierry Chappuis" <th*****@mujigka.chwrote in message
news:11*********************@i42g2000cwa.googlegro ups.com...
Hi,

I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. I'm studying the GObject library and Laurent
Deniau's OOPC framework published on his web site at
http://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html. The approach is
very instructive. I know that I could do much of this stuff with e.g.
C++, but the intellectual challenge of implementing these concepts with
pure ANSI C is relevant to me.

Are you aware of another approaches?
[...]

Check this crap out:

http://groups.google.com/group/comp....f857051ca4029b
;^)
Nov 17 '06 #36

P: n/a
Roland Pibinger wrote:
Your approach is similar to the results of my experiments with OO in
C. You can increase encapsulation when you only forward declare your
structs (e.g. struct Shape) in the header files.
Unfortunately, your approach precludes automatic function inlining.
Also some functions (e.g. actualShape_draw) can be removed form the header
and made 'private', i.e. static, in the respecive *.c file.
This would preclude any explicit call to function actualShape_draw.
An optimizing C++ compiler will elide the virtual {messenger} function
and call the actual function directly
if it can determine the actual type at compile time.

----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
Nov 18 '06 #37

P: n/a
"E. Robert Tisdale" wrote:
>
.... snip ...
>
This would preclude any explicit call to function actualShape_draw.
An optimizing C++ compiler will elide the virtual {messenger}
function and call the actual function directly if it can determine
the actual type at compile time.
This is c.l.c. comp.lang.c++ is thataway ------>

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>

Nov 18 '06 #38

P: n/a
matevzb a écrit :
There's a book/paper called "Object-Oriented Programming with ANSI-C"
by Axel-Tobias Schreiner, available as a PDF at
http://www.planetpdf.com/codecuts/pdfs/ooc.pdf. It explores this area
to a great extend and I'd really recommend it.

--
WYCIWYG - what you C is what you get
Hi,

The Schreiner's approach uses heavy awk preprocessing, and too many
generic (void *) pointers. It is not the most convincing paper I've
read on the subject.

Thank you for your contribution

Thierry

Nov 18 '06 #39

P: n/a

Chris Thomasson a écrit :
"Thierry Chappuis" <th*****@mujigka.chwrote in message
news:11*********************@i42g2000cwa.googlegro ups.com...
Hi,

I'm interested in techniques used to program in an object-oriented way
using the C ANSI language. I'm studying the GObject library and Laurent
Deniau's OOPC framework published on his web site at
http://ldeniau.web.cern.ch/ldeniau/html/oopc/oopc.html. The approach is
very instructive. I know that I could do much of this stuff with e.g.
C++, but the intellectual challenge of implementing these concepts with
pure ANSI C is relevant to me.

Are you aware of another approaches?

[...]

Check this crap out:

http://groups.google.com/group/comp....f857051ca4029b

Thank you for the link! Bookmarked!

Thierry

Nov 18 '06 #40

P: n/a
On Fri, 17 Nov 2006 16:37:35 -0800, "E. Robert Tisdale" wrote:
>Roland Pibinger wrote:
>Your approach is similar to the results of my experiments with OO in
C. You can increase encapsulation when you only forward declare your
structs (e.g. struct Shape) in the header files.

Unfortunately, your approach precludes automatic function inlining.
No encapsulation means no OO. You can't have both at the same time :-)
>Also some functions (e.g. actualShape_draw) can be removed form the header
and made 'private', i.e. static, in the respecive *.c file.

This would preclude any explicit call to function actualShape_draw.
An optimizing C++ compiler will elide the virtual {messenger} function
and call the actual function directly if it can determine the actual
type at compile time.
But isn't polymorphism the point of the whole exercise?

Best regards,
Roland Pibinger
Nov 18 '06 #41

P: n/a
Roland Pibinger wrote;
On Fri, 17 Nov 2006 16:37:35 -0800, "E. Robert Tisdale" wrote:
>Roland Pibinger wrote:
>>Your approach is similar to the results of my experiments with OO in
C. You can increase encapsulation when you only forward declare your
structs (e.g. struct Shape) in the header files.
Unfortunately, your approach precludes automatic function inlining.

No encapsulation means no OO. You can't have both at the same time :-)
You probably meant "data hiding".
The C computer programming language allows you to encapsulate data
[in a struct] but it doesn't support data hiding at all.
Using an opaque data types
(publishing a struct declaration without publishing it's definition)
precludes some compile time optimizations.
>>Also some functions (e.g. actualShape_draw) can be removed form the header
and made 'private', i.e. static, in the respecive *.c file.
This would preclude any explicit call to function actualShape_draw.
An optimizing C++ compiler will elide the virtual {messenger} function
and call the actual function directly if it can determine the actual
type at compile time.

But isn't polymorphism the point of the whole exercise?
Yes, but there is no reason
why that should preclude non-polymorphic applications.

----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
Nov 18 '06 #42

P: n/a
"E. Robert Tisdale" <ed***@netwood.netwrites:
[...]
You probably meant "data hiding".
The C computer programming language allows you to encapsulate data
[in a struct] but it doesn't support data hiding at all.
It doesn't? At all?
Using an opaque data types
(publishing a struct declaration without publishing it's definition)
precludes some compile time optimizations.
Ah, so it *does* support data hiding.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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.
Nov 18 '06 #43

P: n/a
In article <45**************@news.utanet.at>,
Roland Pibinger <rp*****@yahoo.comwrote:
>No encapsulation means no OO.
No encapsulation mean no points from the B&D end of the OO cabal, but
who cares?

-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.
Nov 18 '06 #44

P: n/a
"Thierry Chappuis" <th*****@mujigka.chwrote in message
news:11**********************@h54g2000cwb.googlegr oups.com...
Chris Thomasson a écrit :
>>"Thierry Chappuis" <th*****@mujigka.chwrote in message
news:11*********************@i42g2000cwa.googlegr oups.com...
Hi,
I'm interested in techniques used to program in an object-oriented way
using the C ANSI language.
[...]
>Are you aware of another approaches?

[...]
>>Check this crap out:

http://groups.google.com/group/comp....f857051ca4029b
"Thierry Chappuis"
>>>Thank you for the link! Bookmarked!
No problem... The technique works very well, IMHO. Its a quick, clear and
clean method for supporting basic OO programming in pure ANSI C. I like it
better than C++ in some respects; I am a C/Assembly Language programmer at
heart...

;^)
Nov 18 '06 #45

P: n/a
On Sat, 18 Nov 2006 20:32:41 GMT, Keith Thompson wrote:
>"E. Robert Tisdale" writes:
[...]
>You probably meant "data hiding".
The C computer programming language allows you to encapsulate data
[in a struct] but it doesn't support data hiding at all.
There have been many discussions whether encapsulation and information
hiding are the same or whether one is a means for the other. Let's
assume we mean that data should not be accessible from the 'outside'.
>It doesn't? At all?
>Using an opaque data types
(publishing a struct declaration without publishing it's definition)
precludes some compile time optimizations.

Ah, so it *does* support data hiding.
I've always wondered why C programmers often unnecessarily give up
encapsulation. You can frequently see code like the following:

struct my_struct {
// some data
};
typedef struct my_struct my_struct;

my_struct* init (int i);
int do_something (my_struct* p, int n, float f);
// more functions
void cleanup (my_struct* p);

In the above example the my_struct definition in the header file is
unnecessary, a forward declaration (struct my_struct;) is sufficient.
The user not only gets access to 'private' data but also the my_struct
data become part of the published interface. This means that future
releases of the code cannot alter that data any more (not even
rearrange them) without potentially breaking existing code. Sometimes
the (generous) use of macros prevents encapsulation but in many cases
lack of encapsulation seems to be just an oversight of the programmer.

Best regards,
Roland Pibinger
Nov 19 '06 #46

P: n/a
Roland Pibinger wrote:
I've always wondered
why C programmers often unnecessarily give up encapsulation.
You can frequently see code like the following:

struct my_struct {
// some data
};
typedef struct my_struct my_struct;

my_struct* init (int i);
int do_something (my_struct* p, int n, float f);
// more functions
void cleanup (my_struct* p);

In the above example,
the my_struct definition in the header file is unnecessary.
A forward declaration (struct my_struct;) is sufficient.
The user not only gets access to 'private' data but, also,
the my_struct data become part of the published interface.
This means that future releases of the code cannot alter that data any more
(not even rearrange them) without potentially breaking existing code.
Sometimes the (generous) use of macros prevents encapsulation but, in many cases,
lack of encapsulation seems to be just an oversight of the programmer.
This is poor programming practice.
It compels the programmer to create an uninitialized variable.

It would be better to define a pseudo-constructor

inline
my_struct my_struct_create(int i) {
my_struct value;
// initialize value
return value;
}

and a destructor

inline
void my_struct_destroy(const my_struct* p) {
}
which you might use like this

const
my_struct t = my_struct(13);

// . . .

my_struct_destroy(&t);

Function do_something should not modify *p
and should be declared as

inline
int do_something (const my_struct* p, int n, float f);

If the object really is a container,
you must provide methods that permit users to modify them.

This is a lot safer and more reliable than the methods
that you have suggested. It also allows the C compiler
to inline the functions to improve performance and efficiency.
The C computer programming language does not support data hiding.
Opaque data types may preclude certain optimizations.

----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
Nov 19 '06 #47

P: n/a
"Roland Pibinger" <rp*****@yahoo.comwrote in message
news:45**************@news.utanet.at...
On Sat, 18 Nov 2006 20:32:41 GMT, Keith Thompson wrote:
>>"E. Robert Tisdale" writes:
[...]
>>You probably meant "data hiding".
The C computer programming language allows you to encapsulate data
[in a struct] but it doesn't support data hiding at all.

There have been many discussions whether encapsulation and information
hiding are the same or whether one is a means for the other. Let's
assume we mean that data should not be accessible from the 'outside'.
>>It doesn't? At all?
>>Using an opaque data types
(publishing a struct declaration without publishing it's definition)
precludes some compile time optimizations.

Ah, so it *does* support data hiding.

I've always wondered why C programmers often unnecessarily give up
encapsulation. You can frequently see code like the following:

struct my_struct {
// some data
};
typedef struct my_struct my_struct;
[...]
header
----------

typedef struct mystuff_s *mystuff_t;

extern int mystuff_alloc(mystuff_t*, /* config */);
/* whatever */
source
----------

#include "header"
struct mystuff_s {
/* whatever */
};
int mystuff_alloc(mystuff_t *_pthis, /* config */) {
if (_pthis && /* config is valid */) {
mystuff_t _this = malloc(sizeof(*_this));
if (_this) {
if (/* config of '_this' succeeds */) {
*_pthis = _this;
return 1;
}
}
free(_this);
}

return 0;
}

/* whatever */

It's that simple to hide data-structures that are too sensitive to be in the
hands of a user... Of course "they" can disassemble your code and figure
things out real good, then create a definition of your data-structure(s) for
themselves... Nothing is "crowbar" proof here... Its as simple as following
your pointer and recording all of the offsets from every load/store that
deals with it...

;^)
Nov 19 '06 #48

This discussion thread is closed

Replies have been disabled for this discussion.