"data hiding" prototype code

S

sofeng

I'm not sure if "data hiding" is the correct term, but I'm trying to
emulate this object-oriented technique. I know C++ probably provides
much more than my example, but I'd just like some feedback to find out
if I've done anything wrong. Also, I am working on this for an
embedded environment, so if there are great inefficiencies with this
code, I'd like to know that also. I realize there is overhead with
using an "accessor" function.

I'm trying to:
1.) "hide" data (variables declared as static at file scope) within a
file (algorithm.c)
2.) manipulate the data using an algorithm function (Algorithm())
3.) provide external access to the data using an "accessor" function
(GetAlgorithmData())

Here is my code:

main.c:
#include <stdio.h>
#include "algorithm.h"

int main(void)
{
const ALGORITHM_DATA *alg_ptr;

Algorithm();
GetAlgorithmData(&alg_ptr);
/*alg_ptr->data1 = 99.9;*/ /* This is not allowed */
printf("%f\n", alg_ptr->data1);
printf("%f\n", alg_ptr->data2);
printf("%f\n", alg_ptr->data3);

return 0;
}

algorithm.c:
#include "algorithm.h"

static ALGORITHM_DATA alg;

void GetAlgorithmData(const ALGORITHM_DATA **out)
{
*out = &alg;
}

void Algorithm(void)
{
alg.data1 = 1.0;
alg.data2 = 2.0;
alg.data2 = 3.0;
}

algorithm.h:
#ifndef ALGORITHM_H_
#define ALGORITHM_H_

typedef struct {
double data1;
double data2;
double data3;
} ALGORITHM_DATA;

void GetAlgorithmData(const ALGORITHM_DATA **out);
void Algorithm(void);

#endif /*ALGORITHM_H_*/
 
B

bluejack

I'm not sure if "data hiding" is the correct term, but I'm trying to
emulate this object-oriented technique.

I like to call it encapsulation.
I'd just like some feedback to find out
if I've done anything wrong.

I think there are some things you can do to improve your strategy
here, comments to follow.
I realize there is overhead with using an "accessor" function.

There are, and there are a couple of ways to mitigate that. However,
unless your accessors are being called in a tight loop, it's probably
not an issue you need to solve.
I'm trying to:
1.) "hide" data (variables declared as static at file scope) within a
file (algorithm.c)

First of all, making the variables static at file scope doesn't really
achieve the goal of encapsulation, particularly when you publish the
struct definition in the header. Secondly, static variables at file
scope are not much better than globals: they're certainly not thread
safe, and you open yourself to other sorts of errors as well.
2.) manipulate the data using an algorithm function (Algorithm())
3.) provide external access to the data using an "accessor" function
(GetAlgorithmData())

Your design does not make it clear who "owns" this data. An algorithm
is typically a particular pattern applied to someone else's data,
although it may store some of it's own in the process. Thus, using
"Algorithm" as the generic placeholder for your OO class could be
confusing. Typical algorithms will *take* data and return *results*.

However, assuming that Algorithm really does own this data, I would
define the struct inside the .c file, providing the typedef in the .h
file. *This* hides your data. Algorithm() can return a pointer to this
type, and then you can call accessors with the pointer to obtain
individual elements of the data.

Don't have time to rewrite your code, so I hope that helps.

-bluejack
 
J

jacob navia

bluejack a écrit :
First of all, making the variables static at file scope doesn't really
achieve the goal of encapsulation, particularly when you publish the
struct definition in the header. Secondly, static variables at file
scope are not much better than globals: they're certainly not thread
safe, and you open yourself to other sorts of errors as well.

This is a very important point.

You should put in the .h files just:

typedef struct data;

hiding ALL the definitions of data from external user programs.

This has many advantages:

1) Impossible for your user to know ANYTHING about what is behind data.
2) Can't allocate new data structures but MUST pass through YOUR
allocation.
3) You publish the interface with accessor/setter functions.
4) You can change the structure layout at any time without needing
to recompile any user code.
 
S

sofeng

Thank you for your reply. See my comments below.

First of all, making the variables static at file scope doesn't really
achieve the goal of encapsulation, particularly when you publish the
struct definition in the header. Secondly, static variables at file
scope are not much better than globals: they're certainly not thread
safe, and you open yourself to other sorts of errors as well.

I'm not sure what you mean by "publish the struct definition in the
header". I only put the typedef in the header-- that doesn't publish
the struct definition, right?
Your design does not make it clear who "owns" this data. An algorithm
is typically a particular pattern applied to someone else's data,
although it may store some of it's own in the process. Thus, using
"Algorithm" as the generic placeholder for your OO class could be
confusing. Typical algorithms will *take* data and return *results*.

However, assuming that Algorithm really does own this data, I would
define the struct inside the .c file, providing the typedef in the .h
file. *This* hides your data. Algorithm() can return a pointer to this
type, and then you can call accessors with the pointer to obtain
individual elements of the data.

I realize that the name "Algorithm" might be confusing. Maybe I should
have called it "Object". My intention is that "algorithm.c" "owns" the
data. I did define the struct inside the .c file (it is named "alg")
and I provided the typedef in the header file ( named
"ALGORITHM_DATA"). Maybe my naming was confusing-- maybe I should have
named it "AlgorithmDataType"? I do not want Algorithm() to directly
return the pointer to the data because its caller does not use the
data directly. I want to be able to use algorithm.c's data from
another function, say, Algorithm2(), which does not call Algorithm().
I want Algorithm2() to call algorithm.c's accessor function,
GetAlgorithmData() to get a pointer to a const ALGORITHM_DATA. I put
the const qualifier so that Algorithm2() would not be able to modify
the data in algorithm.c. I realize this calling structure was not
evident in my over-simplified example. I modified my example to
include Algorithm2(). Let me know if I have misunderstood you.

-sofeng

main.c:
#include "algorithm.h"
#include "algorithm2.h"

int main(void)
{
Algorithm();
Algorithm2();

return 0;
}

algorithm.c:
#include "algorithm.h"

static ALGORITHM_DATA alg;

void GetAlgorithmData(const ALGORITHM_DATA **out)
{
*out = &alg;
}

void Algorithm(void)
{
alg.data1 = 1.0;
alg.data2 = 2.0;
alg.data2 = 3.0;
}

algorithm.h:
#ifndef ALGORITHM_H_
#define ALGORITHM_H_

typedef struct {
double data1;
double data2;
double data3;

} ALGORITHM_DATA;

void GetAlgorithmData(const ALGORITHM_DATA **out);
void Algorithm(void);

#endif /*ALGORITHM_H_*/

algorithm2.c:
#include <stdio.h>
#include "algorithm.h"

void Algorithm2(void)
{
const ALGORITHM_DATA *alg_ptr;

GetAlgorithmData(&alg_ptr);
/*alg_ptr->data1 = 99.9;*/ /* This is not allowed */

/* do something with data here */
printf("%f\n", alg_ptr->data1);
printf("%f\n", alg_ptr->data2);
printf("%f\n", alg_ptr->data3);
}

algorithm2.h:
#ifndef ALGORITHM2_H_
#define ALGORITHM2_H_

void Algorithm2(void);

#endif /*ALGORITHM2_H_*/
 
J

Jonas

sofeng said:
Thank you for your reply. See my comments below.



I'm not sure what you mean by "publish the struct definition in the
header". I only put the typedef in the header-- that doesn't publish
the struct definition, right?

In your header file, you have

typedef struct {
double data1;
double data2;
double data3;
} ALGORITHM_DATA;

Instead, separate the typedef and the struct definition into header and
implementation files:

/* foo.h */
typedef struct foo_st foo_t;

/* foo.c */
#include "foo.h"

struct foo_st {
int bar;
};

Now, struct foo_st will be undefined outside of foo.c, which is what you
want to achieve. Pointers to foo_t can be defined by users of foo, but foo_t
objects cannot, leaving your code in charge of this and anything that has to
do with foo_t internals.
 
S

sofeng

Your design does not make it clear who "owns" this data. An algorithm
is typically a particular pattern applied to someone else's data,
although it may store some of it's own in the process. Thus, using
"Algorithm" as the generic placeholder for your OO class could be
confusing. Typical algorithms will *take* data and return *results*.

However, assuming that Algorithm really does own this data, I would
define the struct inside the .c file, providing the typedef in the .h
file. *This* hides your data. Algorithm() can return a pointer to this
type, and then you can call accessors with the pointer to obtain
individual elements of the data.
Thank you for your reply.

I realize that the name "Algorithm" might be confusing. Maybe I should
have named it "Object". My intention was that "algorithm.c" is the
owner of the data. I *did* define the struct inside algorithm.c (named
"alg") and provided the typedef in algorithm.h (named
"ALGORITHM_DATA"). "ALGORITHM_DATA" is a typedef, not a variable
definition. Maybe the name in all caps was confusing. Maybe I should
have named it "AlgorithmDataType".

I didn't want to return a pointer to the structure because in my
actual code, I want a function other than the caller of Algorithm() to
get access to algorithm.c's data directly. For example, I want
Algorithm2(), which does not call Algorithm() to be able to call
GetAlgorithmData() to get access to the data structure defined in
algorithm.c. I realize I did not specify this calling structure in my
oversimplified example. I have added the Algorithm2() code below.
Please let me know if I have misunderstood you.

main.c:
#include "algorithm.h"
#include "algorithm2.h"

int main(void)
{
Algorithm();
Algorithm2();

return 0;
}

algorithm.c:
#include "algorithm.h"

static ALGORITHM_DATA alg;

void GetAlgorithmData(const ALGORITHM_DATA **out)
{
*out = &alg;
}

void Algorithm(void)
{
alg.data1 = 1.0;
alg.data2 = 2.0;
alg.data2 = 3.0;
}

algorithm.h:
#ifndef ALGORITHM_H_
#define ALGORITHM_H_

typedef struct {
double data1;
double data2;
double data3;

} ALGORITHM_DATA;

void GetAlgorithmData(const ALGORITHM_DATA **out);
void Algorithm(void);

#endif /*ALGORITHM_H_*/

algorithm2.c:
#include <stdio.h>
#include "algorithm.h"

void Algorithm2(void)
{
const ALGORITHM_DATA *alg_ptr;

GetAlgorithmData(&alg_ptr);
/*alg_ptr->data1 = 99.9;*/ /* This is not allowed */

/* do something with data here */
printf("%f\n", alg_ptr->data1);
printf("%f\n", alg_ptr->data2);
printf("%f\n", alg_ptr->data3);
}

algorithm2.h:
#ifndef ALGORITHM2_H_
#define ALGORITHM2_H_

void Algorithm2(void);

#endif /*ALGORITHM2_H_*/
 
S

sofeng

Your design does not make it clear who "owns" this data. An algorithm
is typically a particular pattern applied to someone else's data,
although it may store some of it's own in the process. Thus, using
"Algorithm" as the generic placeholder for your OO class could be
confusing. Typical algorithms will *take* data and return *results*.

However, assuming that Algorithm really does own this data, I would
define the struct inside the .c file, providing the typedef in the .h
file. *This* hides your data. Algorithm() can return a pointer to this
type, and then you can call accessors with the pointer to obtain
individual elements of the data.
Thank you for your reply.

I realize that the name "Algorithm" might be confusing. Maybe I should
have named it "Object". My intention was that "algorithm.c" is the
owner of the data. I *did* define the struct inside algorithm.c (named
"alg") and provided the typedef in algorithm.h (named
"ALGORITHM_DATA"). "ALGORITHM_DATA" is a typedef, not a variable
definition. Maybe the name in all caps was confusing. Maybe I should
have named it "AlgorithmDataType".

I didn't want to return a pointer to the structure because in my
actual code, I want a function other than the caller of Algorithm() to
get access to algorithm.c's data directly. For example, I want
Algorithm2(), which does not call Algorithm() to be able to call
GetAlgorithmData() to get access to the data structure defined in
algorithm.c. I realize I did not specify this calling structure in my
oversimplified example. I have added the Algorithm2() code below.
Please let me know if I have misunderstood you.

main.c:
#include "algorithm.h"
#include "algorithm2.h"

int main(void)
{
Algorithm();
Algorithm2();

return 0;
}

algorithm.c:
#include "algorithm.h"

static ALGORITHM_DATA alg;

void GetAlgorithmData(const ALGORITHM_DATA **out)
{
*out = &alg;
}

void Algorithm(void)
{
alg.data1 = 1.0;
alg.data2 = 2.0;
alg.data2 = 3.0;
}

algorithm.h:
#ifndef ALGORITHM_H_
#define ALGORITHM_H_

typedef struct {
double data1;
double data2;
double data3;

} ALGORITHM_DATA;

void GetAlgorithmData(const ALGORITHM_DATA **out);
void Algorithm(void);

#endif /*ALGORITHM_H_*/

algorithm2.c:
#include <stdio.h>
#include "algorithm.h"

void Algorithm2(void)
{
const ALGORITHM_DATA *alg_ptr;

GetAlgorithmData(&alg_ptr);
/*alg_ptr->data1 = 99.9;*/ /* This is not allowed */

/* do something with data here */
printf("%f\n", alg_ptr->data1);
printf("%f\n", alg_ptr->data2);
printf("%f\n", alg_ptr->data3);
}

algorithm2.h:
#ifndef ALGORITHM2_H_
#define ALGORITHM2_H_

void Algorithm2(void);

#endif /*ALGORITHM2_H_*/
 
E

E. Robert Tisdale

sofeng said:
I'm not sure if "data hiding" is the correct term,

The C computer programming language supports encapsulation
but *not* data hiding (like the private label in C++).
C programmers have always used "opaque" data types
when they need to "hide" data.
This is accomplished by publishing a type declaration
in a public header file (algorithm.h in this case)
and defining the new type in a private implementation file
(algorithm.c in this case).
but I'm trying to emulate this object-oriented technique.
I know C++ probably provides much more than my example,
but I'd just like some feedback to find out if I've done anything wrong.
Also, I am working on this for an embedded environment,
so if there are great inefficiencies with this code,
I'd like to know that also.
I realize there is overhead with using an "accessor" function.

I'm trying to:
1.) "hide" data (variables declared as static at file scope) within a
file (algorithm.c)
Don't!

2.) manipulate the data using an algorithm function (Algorithm())

Use my Algorithm_new function instead.
3.) provide external access to the data using an "accessor" function
(GetAlgorithmData())

Use my data1, data2 and data3 functions instead.
> cat algorithm.h
#ifndef ALGORITHM_H
#define ALGORITHM_H

typedef struct Algorithm Algorithm;

Algorithm* Algorithm_new(double, double, double);
void Algorithm_delete(const Algorithm* p);
double data1(const Algorithm*);
double data2(const Algorithm*);
double data3(const Algorithm*);

#endif/*ALGORITHM_H */
> cat algorithm.c
#include "algorithm.h"
#include <stdlib.h>

struct Algorithm {
double data1;
double data2;
double data3;
};

Algorithm* Algorithm_new(double x, double y, double z) {
Algorithm* p = malloc(sizeof(Algorithm));
p->data1 = x;
p->data2 = y;
p->data3 = z;
return p;
}
void Algorithm_delete(const Algorithm* p) {
free((void*)p); }
double data1(const Algorithm* p) {
return p->data1; }
double data2(const Algorithm* p) {
return p->data2; }
double data3(const Algorithm* p) {
return p->data3; }
> cat main.c
#include <stdio.h>
#include "algorithm.h"

int main(int argc, char* argv[]) {
const Algorithm* p = Algorithm_new(1.0, 2.0, 3.0);

printf("%f\n", data1(p));
printf("%f\n", data2(p));
printf("%f\n", data3(p));

Algorithm_delete(p);
return 0;
}
> gcc -Wall -std=c99 -O2 -c algorithm.c
> gcc -Wall -std=c99 -O2 -o main main.c algorithm.o
> ./main
1.000000
2.000000
3.000000
 
S

sofeng

In your header file, you have

typedef struct {
double data1;
double data2;
double data3;
} ALGORITHM_DATA;

Instead, separate the typedef and the struct definition into header and
implementation files:

/* foo.h */
typedef struct foo_st foo_t;

/* foo.c */
#include "foo.h"

struct foo_st {
int bar;
};

Now, struct foo_st will be undefined outside of foo.c, which is what you
want to achieve. Pointers to foo_t can be defined by users of foo, but foo_t
objects cannot, leaving your code in charge of this and anything that has to
do with foo_t internals.

But struct foo_st is synonymous with foo_t so why does it matter that
it is available outside of foo.c? Don't we really care about the
actual variable definition (where the memory is allocated) of type
"struct foo_st" or "foo_t"? For example, for the definition of
foo_var, "foo_t foo_var", foo_var should not be made available outside
of foo.c.
 
J

Jonas

sofeng said:
But struct foo_st is synonymous with foo_t so why does it matter that
it is available outside of foo.c? Don't we really care about the
actual variable definition (where the memory is allocated) of type
"struct foo_st" or "foo_t"? For example, for the definition of
foo_var, "foo_t foo_var", foo_var should not be made available outside
of foo.c.

I'm trying to:
1.) "hide" data (variables declared as static at file scope) within a
file (algorithm.c)
2.) manipulate the data using an algorithm function (Algorithm())
3.) provide external access to the data using an "accessor" function
(GetAlgorithmData())
</context>

Inside foo.c, after the definition of struct foo_st, this will be a complete
type, instances of which can then be defined and its members manipulated.
Everywhere else, this will not be possible. This will "hide" your data. In
order to provide access to and ways to manipulate the data, consider the
following:

/* foo.h */
typedef struct foo_st foo_t;

foo_t * foo_create();
void foo_destroy(foo_t *foo);
void foo_set_bar(foo_t *foo, int bar);
int foo_get_bar(const foo_t *foo);
void foo_manipulate(foo_t* foo);


/* foo.c */
#include "foo.h"

struct foo_st {
int bar;
};

foo_t * foo_create()
{
return malloc (sizeof(foo_t));
}

void foo_destroy(foo_t *foo)
{
free(foo);
}

/* implementation of other functions declared in foo.h should follow...
*/

The user of your code will only include foo.h, and thus will never be able
to access the elements of struct foo_st directly (to them, it will be an
incomplete type, declared but not defined), nor be able to create objects of
type foo_t. The only way to do this will be to use the API you provide. The
_good thing_ here is that the user will not have to care about your
implementation of foo_t, you are free to change anything you please as long
as the API is kept intact.

If you want there to be only *one* foo_t object, as implied in point (3),
then you could declare a static variable in foo.c:

/* foo.h */
typedef struct foo_st foo_t;

foo_t * foo_get_instance();
void foo_manipulate(foo_t *foo);


/* foo.c */
#include "foo.h"

struct foo_st {
int bar;
};

static foo_t foo_instance;
static int is_initialized = 0;

foo_t * foo_get_instance()
{
if (!is_initialized) {
foo.bar = 0;
is_initialized = 1;
}
return &foo_instance;
}

/* implementation of other functions declared in foo.h should follow...
*/

Now, the only foo_t object in existence will be the one defined in foo.c,
since objects of the type cannot be defined anywhere else. This would be
akin to a singleton in the OO-paradigm.
 
S

sofeng

The C computer programming language supports encapsulation
but *not* data hiding (like the private label in C++).
C programmers have always used "opaque" data types
when they need to "hide" data.
This is accomplished by publishing a type declaration
in a public header file (algorithm.h in this case)
and defining the new type in a private implementation file
(algorithm.c in this case).

I'm sorry about my misunderstanding of "opaque" data types in my
previous posts. I was not familiar with this concept. It is not my
goal to create "opaque" data types. I am writing application code and
not API code. My intention was to prevent external functions from
modifying my "hidden" (statically declared) data structures. I did not
want to "hide" the members of the structure. I realize this is
primitive compared to your code (which, I admit, I did not
understand). I am just trying to find a better alternative to using
all global variables which our legacy code currently uses. Note, our
project is relatively small at ~10,000 lines of code. Do you think my
method would be an improvement to using all global variables?
 
E

E. Robert Tisdale

sofeng said:
I'm sorry about my misunderstanding of "opaque" data types in my
previous posts. I was not familiar with this concept. It is not my
goal to create "opaque" data types. I am writing application code and
not API code. My intention was to prevent external functions from
modifying my "hidden" (statically declared) data structures. I did not
want to "hide" the members of the structure. I realize this is
primitive compared to your code (which, I admit, I did not
understand). I am just trying to find a better alternative to using
all global variables which our legacy code currently uses. Note, our
project is relatively small at ~10,000 lines of code. Do you think my
method would be an improvement to using all global variables?

No!

You should avoid global variables including static global variables.
Why can't you use global constants?
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top