Documents -(personal info) -pTA study -largefile * -AutoFS howto -Geschichte der Informatik (* other webserver) Bigger Projects -PFE* -AC-Archive* -ZZIPlib * -XML/G -C.L.F.R. * -XM Tool * Smaller Projects -errno(1) -glib-man -gstdint * ... (patches) -wine-vol-a Older Projects -MPEG split * -XFCE * -htm1-pp -cc-headers -runso -substruct-c -submorph-c ... (patches) -xwpe -xfce 3 Download Area * Sourceforge Project freespace.sf.net Home
generated
|
|
so you can write |
that will provide a struct-definition
as if you had been writing this...
| ||
|
|
Hence you can access the member `a`
without needing to know in which
base type it hade been introduced. Just write `c->a`
when you need it.
note: C++ will read the above code as expected: all member-fields included from the base-struct are treated as public members, so the result is the same as with the C-language base type inclusion syntax here - and remember, C has no access-scope anywhere.
In order to benefit form the inclusion syntax, the compiler must
be able to cast pointers from `C*`
to `B*`
without
warning. This simply means an inheritance type upcast where
the actual pointer value stays untouches, as it would be with
an explicit upcast.
struct B* p; struct C c; p = &c; |
Now you can use all functions written for `struct B`
on
instances of type `struct C`
since it is a base type.
There will be again no warnings if you provide a `struct C*`
in the place of a `struct B*`
-argument to a function.
This works also with the current C-based object-oriented libraries such as GTK, that had not been using the base type inclusion syntax. The compiler will do the type matching against the first field (if that is a struct-instance).
The distributed
testgtk.c
static void /* create modal window helper */ cmw_file (GtkWidget *widget, GtkWidget *parent) { GtkWidget *fs; fs = gtk_file_selection_new("This is a modal file selection dialog"); /* Set as modal */ gtk_window_set_modal (GTK_WINDOW(fs),TRUE); /* And mark it as a transient dialog */ gtk_window_set_transient_for (GTK_WINDOW (fs), GTK_WINDOW (parent)); gtk_signal_connect (GTK_OBJECT(fs), "destroy", GTK_SIGNAL_FUNC(cmw_destroy_cb),NULL); gtk_signal_connect_object (GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), "clicked",GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT (fs)); gtk_signal_connect_object (GTK_OBJECT(GTK_FILE_SELECTION(fs)->cancel_button), "clicked",GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT (fs)); /* wait until destroy calls gtk_main_quit */ gtk_widget_show (fs); gtk_main(); } |
static void /* create modal window helper */ cmw_file (GtkWindow *widget, GtkWindow *parent) { GtkFileSelection *fs; /* GTK-people are severly misguided returning a `GtkWidget*' upon _new */ fs = (GtkFileSelection*) gtk_file_selection_new("This is a modal file selection dialog"); /* Set as modal */ gtk_window_set_modal (fs,TRUE); /* And mark it as a transient dialog */ gtk_window_set_transient_for (fs, parent); gtk_signal_connect (fs, "destroy", GTK_SIGNAL_FUNC(cmw_destroy_cb), NULL); gtk_signal_connect_object (fs->ok_button, "clicked", gtk_widget_destroy, fs); gtk_signal_connect_object (fs->cancel_button, "clicked", gtk_widget_destroy, fs); /* wait until destroy calls gtk_main_quit */ gtk_widget_show (fs); gtk_main(); } |
note: all _new-functions in GTK return 'GtkWidget*'
- well
this is obviously far away from object-oriented programming as far
as even the least novice can tell... and that is what the explicit
cast at the _new-function is needed for.
the current patch provides a matching function that does all the substruct-matching for struct-pointers, but it can not match functions all too well. Anybody wants to do the extension?
The substruct-feature is distributed as a patch against gcc-2.95.
You can get the current substruct.patch
right here. Then go to the directory where you unpacked the gcc-2.95
tree. Then do `cat substruct.patch | patch`
and `make`
a new
compiler. The new compiler does not work differently unless you
enable C++-extensions.
news: gcc-2.95.1 should be fine for this patch - the files used in my patch aren't touched by the update-diff from gcc-2.95 to gcc-2.95.1
Just add `-+` (ie. enable-cplusplus-extensions) or any later gcc standard (like `-std=gnu9x`) that has the C++-extensions as a default. This will enable the substruct-syntax and pointer-aliasing. (and it will also enable '//'-comments...)
You can say `-Wcast-qual`
to switch on additional warnings,
that will show you when the substruct-match was invoked, and what
it yielded. The output will give you fine hints what manual cast
you would have to apply to your code to get rid of warnings
of elder C versions.
The patch carries additional messages that are enabled with `-W`
,
(ie. extra-warnings), which are mainly for debugging.
Of course, you will see warnings about the use of
this unusual construct, so that you don't accidently stumble about it.
You can disable them with -fno-long-long (originally to suppress
warnings on the use of `long long`
type).
The patch installs also two new compilation-standards into the gcc:
latest news: an explicit `-fsubmorph` option does now exist too.
Multiple inheritance in this context would be a no-goer. Although we could include all the members of secondary base types as primary names in the new structure ... but what for? Any function you have been writing for any of the secondary base types is useless since you can not get the address where the secondary base's members start off. You would even not be able to write wrapper functions, it is just the same problem. Instead it is wiser by far to put secondary types as named instances (has-a), and write wrapper functions.
So, any upcast possible in this single-inheritance type-tree
happens to be a `void*`
-cast, ie. the actual address to the
struct does not change. This is very different in C++, where
pointers may as well be magically moved to point to inherited
secondary base types. Hence
struct C : A, B { int c }; void* vp; B* bp; C x; vp = &x; bp = &x; printf ("%p\n", bp); bp = vp; printf ("%p\n", bp); |
I would be pleased to open a discussion on putting the inclusion-syntax for struct-definitions into the official C language standard. If people could be sure about the availability of inclusions, and their simple upcast-relations - well, I suspect it would be widely used in big projects that define very many struct-types. Including GTK of course.
I do like this patch foremost since it does not pollute my GTK-sourcecode with those macro-casts, and at the same time it provides me with static type checking at compile-time - as opposed to dynamic type checking at run-time in GTK (enabled by those very macro-casts). The static type checking is very needed in such huge projects.
May be I get the hooks, so I may make my mind up and add that function-type matching. That would be quite nice.
Otherwise, I'll go to create a new front-end subdir in gcc to hold a "C/C"-frontend. Just look into your old books on "C++ 1.x", and you will know what it is heading for. Especially ... no name mangling! - it is almost impossible to be used from plain C. IMHO contemporary C++ is so different, that it is just a different language being able to read plain C header files (so why are they calling their headers still `*.h' ??)
Things noteworthy different in C with Classes from contempory C++:
- copy operations are always bitwise, not memberwise.
- must use `overload`
-keyword to overload. In my C/C implementation
those will be implicitly inline-functions, so they do not generate
(name-mangled) procedures.
.html
to .htm1
to see the source code)
Any comments wellcome. (sorry, no guestbook here)
(C) Oct'99 Guido Draheim @gmx.de |
| last change 04.Oct'99 |