14

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;
}
Reid
  • 4,376
  • 11
  • 43
  • 75
  • `C` does not have the notion of `private`. Maybe trying looking at `static` global variables. – RageD Apr 25 '12 at 16:40
  • Thus my question. How can I trick C? – Reid Apr 25 '12 at 16:41
  • It depends on what you are trying to do. Since `C` is not OOP (it's function oriented) you will have to work with functions and `struct`s or global variables. – RageD Apr 25 '12 at 16:43
  • C is not Java, so make sure there is a good reason for doing something non-canon before you do it. – Ed S. Apr 25 '12 at 16:51

6 Answers6

19

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 
$ 
Sangeeth Saravanaraj
  • 16,027
  • 21
  • 69
  • 98
10

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).

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
2

You can type:

static int c;

This way, the ".o" won't export the "c" variable.

user1202136
  • 11,171
  • 4
  • 41
  • 62
  • So will I be able to access this from the get and set functions, but not directly? IE. Does `static` Change the scope of the variable? – Reid Apr 25 '12 at 16:43
  • 2
    `static` makes a global variable only visible inside the module it is declared. For example, if another module does `extern int c`, the linker will be unable to find "c". – user1202136 Apr 25 '12 at 16:44
2
static int c;

int get(void) {
    return c;
}

int set(int n) {
    c = n;
}
md5
  • 23,373
  • 3
  • 44
  • 93
1

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.

RageD
  • 6,693
  • 4
  • 30
  • 37
1

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;
}
davidanderle
  • 638
  • 6
  • 12