473,796 Members | 2,872 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Adding the ability to add functions into structures?

So structures are useful to group variables, so you can to refer to a
collection as a single entity. Wouldn't it be useful to also have the
ability to collect variable and functions?

Ask K&R say, C programs consist of variables to store the input and
functions to manipulate them.

This would make C object-oriented - how cool would that be?

Are there any problems with adding the ability to have functions
encapsulated in structures?

Dec 31 '05
47 3900
Emmanuel Delahaye a écrit :
Albert a écrit :
So structures are useful to group variables, so you can to refer to a
collection as a single entity. Wouldn't it be useful to also have the
ability to collect variable and functions?

Ask K&R say, C programs consist of variables to store the input and
functions to manipulate them.

This would make C object-oriented - how cool would that be?

Are there any problems with adding the ability to have functions
encapsulated in structures?

There is no good reason to do that (multipliying function instances ?
Why in the world ?).

The idea behind OOP is that the code is organized around objects and
methods (functions) to manipulate the objects. The objects are designed
to be instanciable, but not the functions. The idea is to have a langage
trick that 'connects' the object and its method:

obj.method()

as in C++, but behind the scene, the method stays unique. What you can
do in C is to store the address of the method (function) in the
structure using a pointer to a function, but it brings nothing really
interesting.

The C-way is rather to define function names like:

type_function()

and to pass the address of the object as the first parameter of these
functions

type_function(t ype *self)

It's also common to have explicit constructors and destructors:

type * type_create()
type_delete(typ e *self)

Note that if you are only using pointers to the objects, the type can be
completely opaque:

typedef struct type type;

A good standard-C-example is the FILE function family.

Constructors / destructors:
fopen() / fclose()

Methods:
fgetc() / fputc() / ferror() etc.


I disagree.

I proposed (in another message in this thread) to program using
interfaces, i.e. arrays of function pointers that can be used
(as it is used routinely in COM programming) to encapsulate
the functions that act in a given object.

This approach has several advantages:
1) You can use common names like Add, Delete, etc, without
polluting the global namespace. The problem with the approach
you propose is that you *have* to prefix the function with
some prefix since you can't have two functions called "Add"
in the same program.

2) You can change or extend the interface without recompiling
client code. For instance, you can add new methods at the
end of the interface ("inheritanc e") without any recompilation.

3) You can "subclass" a functionality of the object by saving the stored
pointer, then replacing it by your own one, without any need
for recompilation.

For instance:

The procedure in the interface "Add" is lacking some functionality.
When you create the object, you save the pointer to the "ADD" function
then you assign a pointer to a new function "Add1", and store it in the
same place:
Object->InterfaceTab le->Add = add1;

All the code that calls that function pointer will continue to
work unmodified using your new "Add1" function. If you save the
pointer to the function you can use it to call the old functionality
in case you do not want to totally replace it but just extend it.

This is much more flexible than C++.

jacob
Jan 1 '06 #31
On 2006-01-01, Richard Heathfield <in*****@invali d.invalid> wrote:
The additional checking for null FILE pointers before calling fclose()
is not a major effort, but it is just annoying enough to earn a place
on the pet peeve list after writing it INT_MAX times.


For sufficiently low values of INT_MAX, anyway.


INT_MAX is required to be at least 32767, of course. Though if you do
not include <limits.h>, you may define it yourself to some other value.
This, of course, should never be done.
Jan 1 '06 #32
On 2006-01-01, Eric Sosman <es*****@acm-dot-org.invalid> wrote:
Keith Thompson wrote:
Mark McIntyre <ma**********@s pamcop.net> writes:
On Sat, 31 Dec 2005 16:29:02 -0500, in comp.lang.c , Eric Sosman
<es*****@a cm-dot-org.invalid> wrote:

Jack Klein wrote:

>[...]
>FILE cannot truly be an opaque type as far standard C is concerned for
>the simple reason that the standard requires some functions to be
>implemente d as macros, and so some of the details must be exposed by
><stdio.h >.

What functions that deal with FILE or FILE* are required
to be macros?

getchar() and getc() may be implemented as a macro, as may the put...
equivalent s.

Any library function may be implemented as a macro. I think assert()
is the only one that's required to be a macro.


There's also setjmp().

However, that wasn't what I asked. Jack Klein wrote that
the Standard *requires* some functions to be implemented as
macros, and this is true. However, I was unable to think of
any FILE-using functions that are *required* to be macros. Can
you suggest any such?

I'm well aware that the Standard *permits* an implementation
to provide macros for any library functions it chooses, so long
as it provides the actual function as well. I'm also aware that
the Standard makes special provision for getc() and putc() (but
not for getchar(), by the way)


getchar does not have any arguments, therefore it wouldn't make sense to
give it permission to evaluate its arguments more than once. I believe
it is implicitly permitted to evaluate the expression (stdin) more than
once, since (stdin) doesn't have side effects.

In other words, #define getchar() getc(stdin) is legal. Particularly
since "The getchar function is equivalent to getc with the argument
stdin ."
that make macro implementations
easier. But does the Standard *require* a macro implementation
for any FILE or FILE* function?

... and what this all comes down to, of course, is whether
FILE can be a fully opaque type. I believe it can be, but both
Jack Klein and Richard Heathfield (two not-to-be-ignored people)
take the opposite view. I'm trying to learn why.


Even if the standard required a macro, that wouldn't mean such a macro
would be required to expose the innards of the file structure.

#define getc(f) getc(f) is legal, and glibc appears to in fact do this,
for some unknown reason.

What did they say that indicated a view that FILE can't be an opaque
type? It's not even really required to be a structure - An
implementation could make FILE an integer type if it wants - or void.
Jan 1 '06 #33
On 2006-01-01, Richard Heathfield <in*****@invali d.invalid> wrote:
Eric Sosman said:
I'm well aware that the Standard *permits* an implementation
to provide macros for any library functions it chooses, so long
as it provides the actual function as well. I'm also aware that
the Standard makes special provision for getc() and putc() (but
not for getchar(), by the way) that make macro implementations
easier. But does the Standard *require* a macro implementation
for any FILE or FILE* function?

... and what this all comes down to, of course, is whether
FILE can be a fully opaque type. I believe it can be, but both
Jack Klein and Richard Heathfield (two not-to-be-ignored people)
take the opposite view. I'm trying to learn why.
Well, to be perfectly honest with you I was just nodding "wisely" at Jack's
assertion rather than think it through myself. (So much for
not-to-be-ignored!)

But now that I'm actually thinking about it (albeit not terribly brightly,
since dinner is moderately imminent), I don't know of anything that would
stop the following program from being strictly conforming:

#include <stdio.h>

int main(void)
{
FILE foo;
return 0;
}

and of course that wouldn't be legal if FILE were truly opaque.


Suppose that FILE is another pointer, though - or an integer. That would
be opaque enough to make no difference.

Or FILE is void and the implementation does not fail to compile on
encountering a field or variable declared void. (There's nothing
forbidding an implementation from emitting a diagnostic on encountering
a declared FILE, or on encountering anything else.)

Besides, there are multiple levels of "opaque". There are types which
can only be declared by the program and passed around by reference.
fpos_t is one.

Whether the definition can be modified while retaining the ability to
execute older binaries is really not the standard's business, since it
doesn't specify compatibility between different implementations .
Also, I was half-thinking (er, yes, I think that's what I mean) of the
possibility that, since getc et al *can* be implemented as macros, it is
necessary to make FILE visible in order to allow implementors the freedom
to implement it as a macro if they so choose. This is probably what Jack
meant, although even now I will freely admit that I haven't thought this
through thoroughly, or at least I don't think I have.


But arguably the implementors can choose not to make it visible if they
do not wish to implement these as macros. Both are under the
implementors' control.
Jan 1 '06 #34
On 2006-01-01, Emmanuel Delahaye <em***@YOURBRAn oos.fr> wrote:
A good standard-C-example is the FILE function family.

Constructors / destructors:
fopen() / fclose()

Methods:
fgetc() / fputc() / ferror() etc.


Speaking of which, I think it would have been better for them to take
the FILE* argument first, to match fprintf. However, the reasons for
this inconsistency lie forgotten in the depths of history. (It strikes
me as especially odd given that UNIX functions that take a file
descriptor number do take it first. Anyone here who was at Bell Labs
around that time have any comment on this? I forget, does DMR read this
newsgroup?)
Jan 1 '06 #35
Jordan Abel wrote:
On 2006-01-01, Emmanuel Delahaye <em***@YOURBRAn oos.fr> wrote:
A good standard-C-example is the FILE function family.

Constructors / destructors:
fopen() / fclose()

Methods:
fgetc() / fputc() / ferror() etc.


Speaking of which, I think it would have been better for them to
take the FILE* argument first, to match fprintf. However, the
reasons for this inconsistency lie forgotten in the depths of
history. (It strikes me as especially odd given that UNIX
functions that take a file descriptor number do take it first.
Anyone here who was at Bell Labs around that time have any
comment on this? I forget, does DMR read this newsgroup?)


If you think of the assembly language historically needed to
implement those functions, all becomes clear (especially if you
have done such implementations ). fprintf needs the FILE first to
allow the variadic mechanisms to functions. For the others,
remember that the usual stack passing mechanism is last argument
pushed first. Thus, for fputc(c, f) the stack at function entry
will look like:

stack-mark
f
c
<top of stack>

This allows the routine to examine c and decide on such things as
'does this get printed', or 'should I convert into a tab sequence'
before worrying about the actual destination. This preliminary
work can be done without disturbing the stack-mark or f.

In this case the gain is fairly small. However when the parameters
include such things as fieldsize or precision, the gains can be
significant.

--
"If you want to post a followup via groups.google.c om, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell. org/google/>
Jan 1 '06 #36
Jordan Abel <ra*******@gmai l.com> writes:
On 2006-01-01, Richard Heathfield <in*****@invali d.invalid> wrote: [...]
But now that I'm actually thinking about it (albeit not terribly brightly,
since dinner is moderately imminent), I don't know of anything that would
stop the following program from being strictly conforming:

#include <stdio.h>

int main(void)
{
FILE foo;
return 0;
}

and of course that wouldn't be legal if FILE were truly opaque.


I think we need to define just what we mean by "opaque".

FILE is IMHO sufficiently opaque as far as the standard is concerned;
it's not impossible to peek into its innards, but any program that
does so is non-portable -- not just in the pedantic "the standard
doesn't guarantee anything" sense, but in the sense that it will break
when ported to a different platform.

(I'm assuming here that the definition of type FILE really does differ
across implementations ; I've never actually checked it.)
Suppose that FILE is another pointer, though - or an integer. That would
be opaque enough to make no difference.

Or FILE is void and the implementation does not fail to compile on
encountering a field or variable declared void. (There's nothing
forbidding an implementation from emitting a diagnostic on encountering
a declared FILE, or on encountering anything else.)


The standard specifically requires FILE to be an object type. I
suppose an implementation could act as if void is an object type, but
IMHO that goes beyond what "conforming " means.

--
Keith Thompson (The_Other_Keit h) 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.
Jan 1 '06 #37
"Chuck F. " <cb********@yah oo.com> writes:
Jordan Abel wrote:

[...]
Speaking of which, I think it would have been better for them to
take the FILE* argument first, to match fprintf. However, the
reasons for this inconsistency lie forgotten in the depths of
history. (It strikes me as especially odd given that UNIX
functions that take a file descriptor number do take it first.
Anyone here who was at Bell Labs around that time have any
comment on this? I forget, does DMR read this newsgroup?)


If you think of the assembly language historically needed to implement
those functions, all becomes clear (especially if you have done such
implementations ). fprintf needs the FILE first to allow the variadic
mechanisms to functions. For the others, remember that the usual
stack passing mechanism is last argument pushed first. Thus, for
fputc(c, f) the stack at function entry will look like:

stack-mark
f
c
<top of stack>

This allows the routine to examine c and decide on such things as
'does this get printed', or 'should I convert into a tab sequence'
before worrying about the actual destination. This preliminary work
can be done without disturbing the stack-mark or f.

In this case the gain is fairly small. However when the parameters
include such things as fieldsize or precision, the gains can be
significant.


You seem to be assuming that the generated code can't easily access
items lower on the stack before accessing items higher on the stack.
In all the assembly languages I'm familiar with, it's easy to access
any item on the stack (within reason) by using a
stack-pointer-plus-offset addressing mode. All parameters are
available simultaneously and equally easily. (Some CPUs might limit
the offset to some small value, but plenty for a couple of
parameters.)

Historically, I know this is true for the PDP-11. What about the
PDP-7 (isn't that the first system where C was implemented)?

Did some CPUs actually require upper stack items to be popped before
lower stack items could be accessed?

--
Keith Thompson (The_Other_Keit h) 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.
Jan 1 '06 #38
Keith Thompson wrote:
[...]
The standard specifically requires FILE to be an object type. I
suppose an implementation could act as if void is an object type, but
IMHO that goes beyond what "conforming " means.


So it does; I think that clears up my confusion. Jack
Klein was right when he said FILE cannot be an opaque type,
but it's not because of "the simple reason that the standard
requires some functions to be implemented as macros." Rather,
it's because 7.19.1/2 requires that FILE be "an object type"
and 6.2.5/1 says that object types "fully describe" objects.
There's no formal definition of "opaque," but it appears
antithetical to "full description."

Thanks to Keith, and to Richard Heathfield for making
the point in a slightly different way.

--
Eric Sosman
es*****@acm-dot-org.invalid
Jan 1 '06 #39
Eric Sosman <es*****@acm-dot-org.invalid> writes:
Keith Thompson wrote:
[...]
The standard specifically requires FILE to be an object type. I
suppose an implementation could act as if void is an object type, but
IMHO that goes beyond what "conforming " means.


So it does; I think that clears up my confusion. Jack
Klein was right when he said FILE cannot be an opaque type,
but it's not because of "the simple reason that the standard
requires some functions to be implemented as macros." Rather,
it's because 7.19.1/2 requires that FILE be "an object type"
and 6.2.5/1 says that object types "fully describe" objects.
There's no formal definition of "opaque," but it appears
antithetical to "full description."

Thanks to Keith, and to Richard Heathfield for making
the point in a slightly different way.


But 7.19.1 says that FILE is

an object type capable of recording all the information needed to
control a stream, including [a bunch of stuff]

It doesn't necessarily have to record the information *directly*. I
can imagine FILE being a typedef for void* (making FILE* void**);
internally the void* can be converted to a pointer to a structure
containing the actual information.

Or if you want the information stored directly in the FILE, make it an
appropriately sized array of unsigned char.

It's probably not worth the effort, though. Even if FILE is a typedef
for a struct containing the required information explicitly, the fact
that the standard says nothing about the content makes it sufficiently
opaque for most purposes. Any scheme to hide the information can be
circumvented by a programmer sufficiently determined to shoot himself
in the foot.

--
Keith Thompson (The_Other_Keit h) 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.
Jan 1 '06 #40

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
741
by: Bob Rock | last post by:
Hello, in the last few days I've made my first few attempts at creating mixed C++ managed-unmanaged assemblies and looking aftwerwards with ILDASM at what is visible in those assemblies from a managed point-of-view I've noticed that: 1) for each managed and unmanaged C function (not C++ classes) I get a public managed static method (defined on a 'Global Functions' class) in the generated assembly with an export name of the form...
5
28676
by: Angel | last post by:
Is there some way to add a C-header file into a C# project? The problem is that this .h file contains several complex structures (over 20) that are used by some unmanaged code. These functions receive these defined structs as parms and modify them during execution. Basically, it'd be something siomple like this (but in C#): #include <parms.h> W32_PARM parm;
11
2584
by: ruffiano | last post by:
A colleague of mine who is a C developer wrote several functions in C which I now need to invoke in my C++ application. This is normally not a problem except that the header file that he wrote contains also several structures and #defines, which I need to use in my C++ application. What is the best way to use the C functions, structures and defines in my code without upsetting the compiler / linker? For the C functions I know I need...
0
9527
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10453
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10223
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10172
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10003
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7546
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5441
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
4115
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3730
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.