Reputation: 4534
I am working in C, and have some variables that I don't want to be global, but I do want to have get and set methods for them that can be accessed "Globaly" outside of the file. I am used to doing this in Java, but C is very different in this manner. Basically I am looking for something that follows this pseudo Code, but I have not been able to find anywhere with examples that I might look at.
main.c
#include data.h
set(b);
datalog.c
#include data.h
get(b);
data.c
private int c;
set(b){
c = b;
}
get(c){
return c;
}
Upvotes: 15
Views: 48921
Reputation: 668
You can improve on @RageD's answer by using function pointers:
#ifndef MYCLASS_H
#define MYCLASS_H
/********************************* MyClass.h **********************************/
// Typedef function pointers for usage clarity
typedef int (*GetInt)();
typedef void (*SetInt)();
typedef struct MyClass {
int Value;
GetInt GetValue;
SetInt SetValue;
} MyClass_t;
// Make the default class accessible to other modules
extern MyClass_t new_MyClass;
#endif
/********************************* MyClass.c **********************************/
#include <stdio.h>
static int getValue(MyClass_t* obj){
if(obj == NULL)
return -1;
return obj->Value;
}
static void setValue(MyClass_t* obj, int value){
if(obj == NULL)
return;
obj->Value = value;
}
// Default "constructor" of MyClass
MyClass_t new_MyClass = {0, &getValue, &setValue};
/*********************************** main.c ***********************************/
//#include "MyClass.h"
int main(){
// Create a default instance of the class
MyClass_t myClass = new_MyClass;
// Call the private (static) Getter function --> Prints 0
printf("%d\n", myClass.GetValue(&myClass));
// Set the instance's value by the Setter function
myClass.SetValue(&myClass, 9);
// Prints 9
printf("%d\n", myClass.GetValue(&myClass));
return 0;
}
Upvotes: 1
Reputation: 70939
If you want private variables in c, there are a number of techniques that can approximate a private variable, but the C language actually doesn't have a "protection" concept that extends to private, public, protected (as C++ does).
C will show the name of any variable (it's a requirement in C) so you must approach it with the idea of information hiding the type of the variable (making dereferencing quite difficult).
One trick is to define the variable as an void*
with the actual variable type being known in only one .c
module.
/* somefile.h */
extern void* counter;
/* somefile.c */
#include "somefile.h"
int actualCounter = 0;
void* counter = &actualCounter;
/* otherfile.c */
#include "somefile.h"
// we can see "counter", but we cannot "use" it here; because we don't have access
// to the real "hidden" type of "int".
A better method is to extend this idea using the struct
keyword, and make pseudo-methods, like so
/* person.h */
struct s_person;
typedef Person struct s_person;
Person* new_Person(char* name);
void delete_Person(Person* person);
void Person_setName(Person* person, char* name);
char* Person_getName(Person* person);
/* person.c */
struct s_person {
char* name;
};
Person* new_Person(char* name) {
Person* object = (Person*)malloc(sizeof(struct s_person));
// duplicate the string for more security, otherwise constructor
// could manipulate the "private" string after construction.
object->name = strdup(name);
return object;
}
void delete_Person(Person* person) {
// some implementations pass a Person** to set the reference to 0
// this implementation requires that the caller sets his own references to 0
free(person->name);
free(person);
}
void Person_setName(Person* person, char* name) {
// free the old
free(person->name);
// duplicate the new to provide "out of simulated class" modification by malicious
// name setter.
person->name = strdup(name);
}
char* Person_getName(Person* person) {
// must return a copy, otherwise one can manipulate name
// from reference provided by Person_getName(...);
return strdup(person->name);
}
/* otherfile.c */
#include "Person.h"
/* Now we can hold Person "simulated objects", but we cannot */
/* manipulate their "state" without using the C simulated object */
/* methods */
int main(int argc, char** argv) {
Person* bob = new_Person("bob");
printf("%s\n", Person_getName(bob));
delete_Person(bob);
// critical or we hold a pointer to freed memory.
bob = 0;
return 0;
}
Techniques like this have several variants, one is to have a "public struct" with a void* pointer to the "private struct". One is to include the "methods" as function pointers in the "public struct" (a step towards supporting polymorphism), one is to actually write a full and proper C++ type system which attempts to resolve things exactly as C++ would (class hierarchies, polymorphisim, late binding, information hiding, etc).
Basically, you can get some "object-oriented-ness" without too much work, but as you add more features of -ornamentation, you will add more glue code (until it is much simpler to actually use an object-oriented programming language).
Upvotes: 10
Reputation: 6823
By your example, you can try using some struct
with this information. A struct
is like a class
with only public member variables (i.e. no functions). So consider something as follows
#include <stdio.h>
typedef struct _somestruct
{
int c;
} theStruct;
int getC(theStruct* obj)
{
if(obj == NULL)
return -1;
return obj->c;
}
void setC(theStruct* obj, int val)
{
if(obj == NULL)
return;
obj->c = val;
}
int main()
{
theStruct myStruct;
setC(&myStruct, 5);
printf("%d\n", getC(&myStruct));
return 0;
}
As you can see, C
works only with objects and functions. But to get a global variable across all files, try static int c = 0;
The example above is nearly as close as you can possibly get to a "java-style" convention.
Upvotes: 1
Reputation: 16617
You make the variable static
. When a global variable is made static
, its scope is restricted to the current file.
An example is as follows:
Filename: main.c
#include <stdio.h>
#include "header.h"
extern int get();
extern void set(int);
int main()
{
set(10);
printf("value = %d \n", get());
set(20);
printf("value = %d \n", get());
set(30);
printf("value = %d \n", get());
set(40);
printf("value = %d \n", get());
return 0;
}
Filename: header.h
#include <stdio.h>
int get(void);
void set(int);
Filename: header.c
#include "header.h"
static int value = 0;
int get(void)
{
return value;
}
void set(int new_value)
{
value = new_value;
}
Output:
$ gcc -Wall -o main main.c header.h header.c
$ ./main
value = 10
value = 20
value = 30
value = 40
$
Upvotes: 20
Reputation: 11567
You can type:
static int c;
This way, the ".o" won't export the "c" variable.
Upvotes: 2