【问题标题】:C Private Variables Get and Set methodsC 私有变量 Get 和 Set 方法
【发布时间】:2012-04-25 16:38:46
【问题描述】:

我在 C 中工作,并且有一些我不想成为全局变量,但我确实希望为它们提供可以在文件外部“全局”访问的 get 和 set 方法。我习惯在 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;
}

【问题讨论】:

  • C 没有private 的概念。也许尝试查看static 全局变量。
  • 这就是我的问题。我怎样才能欺骗 C?
  • 这取决于你想要做什么。由于 C 不是 OOP(它是面向函数的),因此您必须使用函数和 structs 或全局变量。
  • C 不是 Java,所以在做之前确保有充分的理由去做一些非规范的事情。

标签: c private-members private-methods


【解决方案1】:

您创建变量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 
$ 

【讨论】:

  • 不需要在main.c的顶部声明get()set()。 - 这就是你首先创建标题的原因。
  • 不需要在标题中包含stdio.h。 - 标题中的代码没有使用它。
【解决方案2】:

如果你想在 c 中使用私有变量,有许多技术可以近似私有变量,但 C 语言实际上没有延伸到私有、公共、受保护的“保护”概念(就像 C++ 那样)。

C 将显示任何变量的 name(这是 C 中的要求),因此您必须通过隐藏变量的 type 信息的想法来处理它(使解除引用相当困难)。

一个技巧是将变量定义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 功能,您将添加更多胶水代码(直到它简单得多实际使用面向对象的编程语言)。

【讨论】:

  • 是否正确:typedef Person struct s_person; ?应该是:typedef struct s_person Person;,对吧?
【解决方案3】:

您可以输入:

static int c;

这样,“.o”不会导出“c”变量。

【讨论】:

  • 那么我是否可以通过 get 和 set 函数访问它,但不能直接访问? IE。 static是否改变了变量的作用域?
  • static 使全局变量仅在声明它的模块内可见。例如,如果另一个模块执行extern int c,则链接器将无法找到“c”。
【解决方案4】:

通过您的示例,您可以尝试在此信息中使用一些 structstruct 就像 class 只有 public 成员变量(即没有函数)。所以考虑如下

#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-style”约定非常接近。

【讨论】:

    【解决方案5】:
    static int c;
    
    int get(void) {
        return c;
    }
    
    int set(int n) {
        c = n;
    }
    

    【讨论】:

      【解决方案6】:

      您可以使用函数指针改进@RageD 的答案:

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

      【讨论】:

        猜你喜欢
        • 2015-08-19
        • 1970-01-01
        • 2013-12-26
        • 1970-01-01
        • 1970-01-01
        • 2018-04-08
        • 2018-02-26
        • 2013-06-22
        • 2016-02-25
        相关资源
        最近更新 更多