Hidden One Instance

I

Immortal Nephi

There are thousands of emulator projects written in C language and
sometimes in assembly language. The programmers always write a
wrapper in the file scope. All member variables and member functions
are located in the file scope, but they are acting to be old-fashioned
global variables and global functions.
The programmers are afraid to write object-oriental programming
because two or three indirections are used to cause overhead on the
CPU so they prefer to use procedural programming instead. They want
critical speed like real time for best performance.
I create a library such as DLL. All global variables are hidden in
the Library.c. Only getter functions are available to the clients.
The library module is designed to have only ONE instance . All global
variables are treated to be one instance. They remain existent from
the beginning of this program throughout to the end.
Please review my source code below. Please let me know if my source
code looks to be the best practice for emulator project. I will
mention multiple instances momentarily.

// Library.h

#ifndef __LIBRARY_H__
#define __LIBRARY_H__

int get_a( void );
int get_b( void );
int get_c( void );

void run( void );

#endif /* __LIBRARY_H__ */



// Library.c

#include "Library.h"

static int a = 0;
static int b = 0;
static int c = 0;

int get_a( void ) { return a; }
int get_b( void ) { return b; }
int get_c( void ) { return c; }

static void modify( void ) { a += 1; b += 2; c += 3; }

void run( void ) { modify(); }



// main.c

#include "Library.h"

int main()
{
run();
int _a = get_a();
int _b = get_b();
int _c = get_c();

return 0;
}

I have another source code below to present multiple instances. The
global variables are no longer to be located in the file scope. They
are now located in the data structure. The data structure is in the
library.h.
The problem is that member variables in the data structure are now
visible to the clients. They are no longer to be protected or
hidden. The clients are able to modify member variables.
The main function has two objects in an array like two instances.
Only object pointer is available in the library.h. The client assigns
first object to the object pointer before they invoke initialize
function and run function.
In other words, they can reassign second object to the same object
pointer. This way, both objects are running at the same time like
multithreading.
Sometimes, programmers prefer to place object pointer in the run
function’s parameter like this run( _obj *p_obj ) when they want to
switch between objects.
Please comment how member variables in the data structure be
protected. Please take a look at my source code below.

// Library.h

#ifndef __LIBRARY_H__
#define __LIBRARY_H__

struct _obj
{
int a;
int b;
int c;
};

extern _obj *p_obj;

int get_a( void );
int get_b( void );
int get_c( void );

void run( void );

void initialize( void );

#endif /* __LIBRARY_H__ */



// Library.c

#include "Library.h"

_obj *p_obj;

int get_a( void ) { return p_obj->a; }
int get_b( void ) { return p_obj->b; }
int get_c( void ) { return p_obj->c; }

static void modify( void ) { p_obj->a += 1; p_obj->b += 2; p_obj->c +=
3; }

void run( void ) { modify(); }

void initialize( void ) { p_obj->a = 0; p_obj->b = 0; p_obj->c = 0; }



// main.c

#include "Library.h"

int main()
{
int _a, _b, _c;
_obj obj[3];

p_obj = &obj[0];
initialize();
run();
_a = get_a();
_b = get_b();
_c = get_c();

p_obj = &obj[1];
initialize();
run();
_a = get_a();
_b = get_b();
_c = get_c();

return 0;
}
 
I

Immortal Nephi

     I'm not sure what you mean by "wrapper" here.

The wrapper means to group member variables and member functions
inside C++ class with wonderful encapsulation so any clients or
functions are unable to access private member variables. I do not
present to talk about C++ class. I talk about file scope as C source
code. All global variables and global functions are located in the
file scope as internal linkage. Only global variables are private in
Library.c so it won't be shown in Library.h.
Do I explain clear?

     Speed is worth working for, once you've measured it and found
that you don't have enough.  Note that on modern machines the penalty
for "two or three indirections" can be many times worse (as a fraction)
than on older machines: CPU's are now a couple orders of magnitude
faster than RAM, and cache misses can hurt badly.




     Good technique, but poor choice of macro name.  Identifiers
beginning with two underscores are reserved, not available for
the programmer's use.  In many contexts, identifiers beginning
with just one underscore are reserved.  Choose another name.

You suggest LIBRARY_H instead of __LIBRARY_H__. I can do this to
follow C rules. You may notice that there are most structs with a tag
name and one underscore such as _obj. You may have heard MAME. MAME
is the one to show one underscore with tag name.
     Remember what I said about identifiers that begin with underscores?
Choose other names.

     Also, C99 allows declarations to come after statements, but the
earlier C90 standard (still widely followed) requires that declarations
come first.  (Just a heads-up, in case you want your code to be usable
with older C implementations.)







     No.  The C language has only one thread of execution.  (There's a
very weak notion of simultaneity in the `volatile' keyword, but not
enough to get multiple threads running.  Nor do signals count: They
operate as if by suspending the rest of the program while the signal
handler runs, so there's still only one execution thread.)

As I said about emulator earlier. If you declare and define more
than one object, it may look like multithreading. I think you are
referring multitasking. For example, struct CPU CPU_Object is only
one object. You create two CPU_Object arrays "obj CPU_Object[2]".
Two CPU_Objects are running at the same time in the one thread of
execution.

     _your _fascination _with _leading _underscores _is _unhealthy.



     You have not defined a type named `_obj'.  (You have defined a
type named `struct _obj', but that's all.)  Are you, by any chance,
writing C++ rather than C?  If so, you'll probably get better advice
in comp.lang.c++ than you will here.

I will follow your advice. No underscore before variable name.
It would be a lot of easier to use prefix name such as g_SName
(struct), g_nName (integer), etc. What happen if you have local
variables without prefix name. You have no way to find if variable is
truly local variable or global variable. You will only put one
underscore before name on the local variable inside function body.
What are you recommending?

int get_a( void );
int get_b( void );
int get_c( void );
void run( void );
void initialize( void );
#endif /* __LIBRARY_H__ */
// Library.c
#include "Library.h"
_obj *p_obj;
int get_a( void ) { return p_obj->a; }
int get_b( void ) { return p_obj->b; }
int get_c( void ) { return p_obj->c; }
static void modify( void ) { p_obj->a += 1; p_obj->b += 2; p_obj->c +=
3; }
void run( void ) { modify(); }
void initialize( void ) { p_obj->a = 0; p_obj->b = 0; p_obj->c = 0; }
// main.c
#include "Library.h"
int main()
{
   int _a, _b, _c;
   _obj obj[3];
   p_obj = &obj[0];
   initialize();
   run();
   _a = get_a();
   _b = get_b();
   _c = get_c();
   p_obj = &obj[1];
   initialize();
   run();
   _a = get_a();
   _b = get_b();
   _c = get_c();
   return 0;
}

     Ugh.  Ugh, ugh, ugh, and *never* think of doing this kind of thing
if you're also thinking about multi-threaded programming.

     The usual technique is for the library's header to describe the
abstract object as an "incomplete type," usually a struct with a tag
but with no elements.  The functions that operate on the object are
declared as dealing in pointers to that incomplete type:

        /* Library.h */
        #ifndef H_LIBRARY
        #define H_LIBRARY

        typedef struct obj Object;

        Object *newObject(void);
        void destroyObject(Object *);

        int get_a(const Object *);
        int get_b(const Object *);
        int get_c(const Object *);

        void run(Object *);

        #endif

Note that since `struct obj' (a.k.a. `Object') is an incomplete type,
the clients have no idea what its internals look like, nor even how
big it is.  Hence the need for a constructor, and it's usually a good
idea to have a matching destructor.

     In the library implementation itself, you finally get around to
completing the type by listing its elements.  The functions inside the
library can "see" the completion, but those outside cannot:

        /* Library.c */
        #include <stdlib.h>
        #include "Library.h"

        struct obj { int a; int b; int c; }

        Object *newObject(void) {
            Object p = malloc(sizeof *p);
            if (p != NULL) {
                p->a = 31;
                p->b = 41;
                p->c = 59;
            }
            return p;  /* NULL if unable to create */
        }

        void destroyObject(Object *p) { free(p); }

        int get_a(const Object *p) { return p->a; }
        int get_b(const Object *p) { return p->b; }
        int get_c(const Object *p) { return p->c; }

        void run(Object *p) {
            p->a += 1;  p->b += 2;  p->c += 3;
        }

     If the library is too big to be contained conveniently in a single
source file, you need a way to "publish" the `struct obj' declaration
to all the library's sources but not to the clients.  The usual way to
do this is to put it in a "LibraryPrivate.h" file that only the library
sources #include.  If you're distributing the library in compiled form,
you wouldn't even distribute "LibraryPrivate.h" (although of course you
still need to distribute "Library.h").

     Get rid of those leading underscores, before they rise up and bite
you in the part you sit on.

Thanks for your advice.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top