C Частные переменные Get и Set методы

Я работаю в C, и у меня есть некоторые переменные, которые я не хочу, чтобы они были глобальными, но я хочу иметь методы get и set для них, к которым можно получить доступ "Globaly" вне файла. Я привык делать это в Java, но C сильно отличается в этом смысле. В основном я ищу что-то, что следует за этим псевдокодом, но я не смог найти нигде с примерами, на которые я мог бы взглянуть.

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;
}

6 ответов

Решение

Вы делаете переменную static, Когда глобальная переменная сделана static, его область ограничена текущим файлом.

Пример таков:

Имя файла: 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;
}

Имя файла: header.h

#include <stdio.h>

int get(void);
void set(int);

Имя файла: header.c

#include "header.h"

static int value = 0;

int get(void)
{
    return value;
}

void set(int new_value)
{
    value = new_value;
}

Выход:

$ gcc -Wall -o main main.c header.h header.c 
$ ./main 
value = 10 
value = 20 
value = 30 
value = 40 
$ 

Если вам нужны закрытые переменные в c, есть ряд методов, которые могут аппроксимировать закрытые переменные, но в языке C на самом деле нет концепции "защиты", которая распространяется на закрытые, публичные, защищенные (как это делает C++).

C покажет имя любой переменной (это требование в C), поэтому вы должны подойти к ней с идеей информации, скрывающей тип переменной (что делает разыменование довольно трудным).

Один трюк состоит в том, чтобы определить переменную как void* фактический тип переменной известен только в одном .c модуль.

 /* 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".

Лучший способ - расширить эту идею, используя struct ключевое слово и создайте псевдо-методы, например

 /* 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;
 }

Методы, подобные этой, имеют несколько вариантов, один из них - иметь "публичную структуру" с указателем void* на "приватную структуру". Один из них заключается в том, чтобы включить "методы" в качестве указателей на функции в "публичную структуру" (шаг к поддержке полиморфизма), а другой - на самом деле написать полную и правильную систему типов C++, которая пытается разрешить вещи точно так же, как C++ (иерархии классов, полиморфизм, позднее связывание, сокрытие информации и т. д.).

По сути, вы можете получить некоторую "объектно-ориентированность" без особой работы, но по мере добавления дополнительных возможностей -ornamentation вы будете добавлять больше связующего кода (пока на самом деле гораздо проще фактически использовать объектно-ориентированный язык программирования).,

Вы можете ввести:

static int c;

Таким образом, ".o" не будет экспортировать переменную "c".

static int c;

int get(void) {
    return c;
}

int set(int n) {
    c = n;
}

Вы можете улучшить ответ @RageD, используя указатели функций:

#ifndef MYCLASS_H
#define MYCLASS_H

/********************************* MyClass.h **********************************/
typedef struct MyClass {
    int  Value;
    int  (*GetValue)();         // Don't specify arguments
    void (*SetValue)();         // Don't specify arguments
} 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;
}

На вашем примере вы можете попробовать использовать некоторые struct с этой информацией. struct это как class только с открытыми переменными-членами (т.е. без функций). Итак, рассмотрим что-то следующее

#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;
}

Как вы видете, C работает только с объектами и функциями. Но чтобы получить глобальную переменную для всех файлов, попробуйте static int c = 0;

Приведенный выше пример почти так же близок, как вы можете прийти к соглашению "в стиле Java".

Другие вопросы по тегам