如何有效地构建C程序

时间:2022-11-13 22:53:28

Let me first say that I've got a fair amount of experience in both C and C++. However, I'm starting a new project in C and I've been working in object-oriented languages for so long (C# and C++) that I am having trouble coming up with an effective way to encapsulate functionality in a procedural language. My first thought was to simply fall back on my OO knowledge and structure it something like:

让我先说,我在C和c++都有相当多的经验。然而,我正在用C启动一个新项目,而且我已经用面向对象语言(c#和c++)工作了很长时间,以至于我在用过程语言封装功能的有效方法上遇到了麻烦。我的第一个想法就是依靠我的OO知识,把它组织成这样:

struct Foo 
{
    int x;
    char *y;
}; 

struct Foo *new_Foo()
{
    return (struct Foo *)malloc(sizeof(struct Foo));
} 

void Foo_member_function(struct Foo *foo, int z)
{
    foo->x = z;    
}

But that just seems tedious and contrary to the spirit of C. Not to mention that it is a poor-man's OO.

但这似乎是乏味的,与c的精神相反,更不用说这是一个穷人的OO。

This program is ultimately going to get fairly sizable, so starting from a good design organization is critical. I imagine with the years of development in C, certain design patterns have developed in how to best structure the code for maintainability. Much like functional programming, I'm hoping that procedural programming has a paradigm that is clean and fairly readable.

这个程序最终会变得相当大,所以从一个好的设计组织开始是至关重要的。我认为,随着C语言多年的发展,在如何为可维护性优化代码结构方面,已经开发出了某些设计模式。就像函数式编程一样,我希望过程式编程具有一种清晰且可读的范式。

Pointers to relevant articles and books are acceptable as well.

指向相关文章和书籍的指针也可以接受。

7 个解决方案

#1


15  

This is quite a normal and sensible practice. But try not to expose the struct layout in header files, so that you have some flexibility in how it's implemented and manage your dependencies better.

这是相当正常和明智的做法。但是尽量不要在头文件中暴露struct布局,这样您就可以在如何更好地实现和管理依赖项方面有一些灵活性。

See Opaque pointer for more details.

有关更多细节,请参见不透明指针。

#2


11  

What you are suggesting is the way I always wrote C programs back in the days when I did such a thing. I don't think it is "poor mans OO", I think it is sensible procedural programming practice.

你说的是我以前写C程序的方式。我不认为这是“可怜的人”,我认为这是合理的程序性编程实践。

I would observe a couple of things about your C code:

关于你的C代码,我想说两点:

  • use typedefs with struct definitions so you don't need to scatter the 'struct' keyword throughout the code
  • 使用带有struct定义的typedefs,这样就不需要在整个代码中分散'struct'关键字
  • only use casts when they are actually needed - the cast on the return value from malloc() is unecessary
  • 只有在实际需要时才使用类型转换—来自malloc()的返回值的类型转换是不必要的

#3


3  

Hmmm... We used to just use naming conventions... Ergo: str* does stuff with what common datastructure? So maybe just take the C# syntax and s/./_/g?

嗯…我们过去只使用命名约定……str*使用什么公共数据结构?所以,也许只需要使用c#语法和s/./_/g?

  • foo_constructor
  • foo_constructor
  • foo_destructor
  • foo_destructor
  • foo_someMethod
  • foo_someMethod
  • foo_someMethod2 // ain't no overloading in ANSI C
  • 在ANSI C中没有重载
  • foo_otherMethod
  • foo_otherMethod

... and there ain't no inheritance ...

…没有遗传……

  • foo2_constructor
  • foo2_constructor
  • foo2_destructor
  • foo2_destructor
  • foo2_someMethod // and there ain't no polymorphism
  • foo2_someMethod //并没有多态性。

But look on the bright side... you can use pointer-to-pointer-to-pointer-to-function-returning-a-pointer-to-pointer-int! Oh the joy!

但从好的方面看……您可以使用pointer-to-pointer-to-pointer-to-function-returning-a-pointer-to-pointer-int !哦,快乐!

My bestest advise is to learn the lessons of Java (and by inference C#) and structure your libraries to NOT have side-effects... more typdefs == less headaches... and if your work-out how to follow this sage advise please let me know ;-)

我最好的建议是学习Java的经验(通过推断c#),并构造您的库,使其不具有副作用……更少的头痛……如果你的健身计划如何遵循这一明智的建议,请让我知道;

Cheers. Keith.

欢呼。基斯。

#4


2  

That's a pretty reasonable way to write a C program. There is another large application out there, which does pretty much the same stuff - called the Linux kernel. Some nearly OO-features used in there:

这是编写C程序的一种非常合理的方式。还有另一个大型应用程序,它做的几乎是相同的事情——Linux内核。其中一些几乎是oo特性:

  • structs and operations on structs for encapsulation just like in your example
  • 结构和对结构的操作进行封装,就像您的示例一样
  • pointers to base structs as a form of poor man's inheritance -- you'll find loads of references to struct kobject in there
  • 作为穷人继承的一种形式,指向基结构体的指针——您将在其中找到大量指向struct kobject的引用
  • macros to generate functions as a replacement for template programming
  • 用于生成函数以替代模板编程的宏

#5


1  

C has been a low-level language and in the respect it would be very useful to organize your data structures in accordance with your code functions and modules.

C是一种低级语言,在这方面,根据代码函数和模块组织数据结构非常有用。

I would suggest that you use typedefs and enumerations wherever you would like to create data objects. Use macros or static functions to initialize, allocate and 'destroy' as required.

我建议您在需要创建数据对象的任何地方使用typedef和枚举。根据需要使用宏或静态函数初始化、分配和“销毁”。

#6


1  

I agree with the suggestions above. You are doing it the best way .. if you want to program in C.

我同意上面的建议。你这样做是最好的方法。如果你想用C编程。

Of course, you could write a pre-processor to automatically generate these declarations and things for you .. maybe use a "Class" declaration ... put the functions you want to be member functions inside the class .. etc.

当然,您可以编写一个预处理器来自动生成这些声明和东西。也许可以使用“类”声明……将你想要成为类成员的函数放在类中。等。

But what we've got here is a simple C++ to C compiler. Why not just program in C++, use a real C++ compiler, use clean interfaces, and just link the C++ code with the C code? What is the reason that you need to code in C vs. C++ anyways? Or if you need to, generate C code from the compiler and compile the output C code together with whatever else you need.

这里我们有一个简单的c++编译器。为什么不使用c++编写程序,使用真正的c++编译器,使用干净的接口,将c++代码与C代码链接起来呢?您需要用C和c++编写代码的原因是什么?或者,如果需要,可以从编译器生成C代码,并将输出的C代码与其他需要的代码一起编译。

#7


0  

I have been working on a project for a little while where the library needs to be in C, but I want to have some form of OO functionality. I am doing something similar to this with a little more detail.

我已经为一个项目工作了一段时间,在这个项目中库需要使用C语言,但是我想要一些形式的OO功能。我正在做类似的事情,有更多的细节。

struct klass {
  char * value;

  void (*set_value) (struct klass *, const char *);
  void (*destroy) (struct klass *);
};

static void
klass_method_set_value (struct klass * k, const char * value) {
  if (k->value == NULL) {
  }
}

static void 
klass_object_desetroy (struct klass * k) {
  free (k);
  k = NULL;
}

static void
klass_method_destroy (struct klass * k) {
  klass_object_destroy (k);
}

static struct klass *
klass_object_init (void) {
  struct klass * obj = (struct klass *) malloc (sizeof (struct klass*) );

  /* members */
  obj->value = NULL;

  /* methods */
  obj->set_value = klass_method_set_value;
  obj->destroy = klass_method_destroy;
  return obj;
}

struct klass * 
klass_new (void) {
  return klass_object_init ();
}

Forgive me if something is wrong; wrote it a little quick.

如果出了什么事,请原谅;写得有点快。

#1


15  

This is quite a normal and sensible practice. But try not to expose the struct layout in header files, so that you have some flexibility in how it's implemented and manage your dependencies better.

这是相当正常和明智的做法。但是尽量不要在头文件中暴露struct布局,这样您就可以在如何更好地实现和管理依赖项方面有一些灵活性。

See Opaque pointer for more details.

有关更多细节,请参见不透明指针。

#2


11  

What you are suggesting is the way I always wrote C programs back in the days when I did such a thing. I don't think it is "poor mans OO", I think it is sensible procedural programming practice.

你说的是我以前写C程序的方式。我不认为这是“可怜的人”,我认为这是合理的程序性编程实践。

I would observe a couple of things about your C code:

关于你的C代码,我想说两点:

  • use typedefs with struct definitions so you don't need to scatter the 'struct' keyword throughout the code
  • 使用带有struct定义的typedefs,这样就不需要在整个代码中分散'struct'关键字
  • only use casts when they are actually needed - the cast on the return value from malloc() is unecessary
  • 只有在实际需要时才使用类型转换—来自malloc()的返回值的类型转换是不必要的

#3


3  

Hmmm... We used to just use naming conventions... Ergo: str* does stuff with what common datastructure? So maybe just take the C# syntax and s/./_/g?

嗯…我们过去只使用命名约定……str*使用什么公共数据结构?所以,也许只需要使用c#语法和s/./_/g?

  • foo_constructor
  • foo_constructor
  • foo_destructor
  • foo_destructor
  • foo_someMethod
  • foo_someMethod
  • foo_someMethod2 // ain't no overloading in ANSI C
  • 在ANSI C中没有重载
  • foo_otherMethod
  • foo_otherMethod

... and there ain't no inheritance ...

…没有遗传……

  • foo2_constructor
  • foo2_constructor
  • foo2_destructor
  • foo2_destructor
  • foo2_someMethod // and there ain't no polymorphism
  • foo2_someMethod //并没有多态性。

But look on the bright side... you can use pointer-to-pointer-to-pointer-to-function-returning-a-pointer-to-pointer-int! Oh the joy!

但从好的方面看……您可以使用pointer-to-pointer-to-pointer-to-function-returning-a-pointer-to-pointer-int !哦,快乐!

My bestest advise is to learn the lessons of Java (and by inference C#) and structure your libraries to NOT have side-effects... more typdefs == less headaches... and if your work-out how to follow this sage advise please let me know ;-)

我最好的建议是学习Java的经验(通过推断c#),并构造您的库,使其不具有副作用……更少的头痛……如果你的健身计划如何遵循这一明智的建议,请让我知道;

Cheers. Keith.

欢呼。基斯。

#4


2  

That's a pretty reasonable way to write a C program. There is another large application out there, which does pretty much the same stuff - called the Linux kernel. Some nearly OO-features used in there:

这是编写C程序的一种非常合理的方式。还有另一个大型应用程序,它做的几乎是相同的事情——Linux内核。其中一些几乎是oo特性:

  • structs and operations on structs for encapsulation just like in your example
  • 结构和对结构的操作进行封装,就像您的示例一样
  • pointers to base structs as a form of poor man's inheritance -- you'll find loads of references to struct kobject in there
  • 作为穷人继承的一种形式,指向基结构体的指针——您将在其中找到大量指向struct kobject的引用
  • macros to generate functions as a replacement for template programming
  • 用于生成函数以替代模板编程的宏

#5


1  

C has been a low-level language and in the respect it would be very useful to organize your data structures in accordance with your code functions and modules.

C是一种低级语言,在这方面,根据代码函数和模块组织数据结构非常有用。

I would suggest that you use typedefs and enumerations wherever you would like to create data objects. Use macros or static functions to initialize, allocate and 'destroy' as required.

我建议您在需要创建数据对象的任何地方使用typedef和枚举。根据需要使用宏或静态函数初始化、分配和“销毁”。

#6


1  

I agree with the suggestions above. You are doing it the best way .. if you want to program in C.

我同意上面的建议。你这样做是最好的方法。如果你想用C编程。

Of course, you could write a pre-processor to automatically generate these declarations and things for you .. maybe use a "Class" declaration ... put the functions you want to be member functions inside the class .. etc.

当然,您可以编写一个预处理器来自动生成这些声明和东西。也许可以使用“类”声明……将你想要成为类成员的函数放在类中。等。

But what we've got here is a simple C++ to C compiler. Why not just program in C++, use a real C++ compiler, use clean interfaces, and just link the C++ code with the C code? What is the reason that you need to code in C vs. C++ anyways? Or if you need to, generate C code from the compiler and compile the output C code together with whatever else you need.

这里我们有一个简单的c++编译器。为什么不使用c++编写程序,使用真正的c++编译器,使用干净的接口,将c++代码与C代码链接起来呢?您需要用C和c++编写代码的原因是什么?或者,如果需要,可以从编译器生成C代码,并将输出的C代码与其他需要的代码一起编译。

#7


0  

I have been working on a project for a little while where the library needs to be in C, but I want to have some form of OO functionality. I am doing something similar to this with a little more detail.

我已经为一个项目工作了一段时间,在这个项目中库需要使用C语言,但是我想要一些形式的OO功能。我正在做类似的事情,有更多的细节。

struct klass {
  char * value;

  void (*set_value) (struct klass *, const char *);
  void (*destroy) (struct klass *);
};

static void
klass_method_set_value (struct klass * k, const char * value) {
  if (k->value == NULL) {
  }
}

static void 
klass_object_desetroy (struct klass * k) {
  free (k);
  k = NULL;
}

static void
klass_method_destroy (struct klass * k) {
  klass_object_destroy (k);
}

static struct klass *
klass_object_init (void) {
  struct klass * obj = (struct klass *) malloc (sizeof (struct klass*) );

  /* members */
  obj->value = NULL;

  /* methods */
  obj->set_value = klass_method_set_value;
  obj->destroy = klass_method_destroy;
  return obj;
}

struct klass * 
klass_new (void) {
  return klass_object_init ();
}

Forgive me if something is wrong; wrote it a little quick.

如果出了什么事,请原谅;写得有点快。