【问题标题】:How to structure a C program effectively如何有效地构建 C 程序
【发布时间】:2009-06-07 12:08:09
【问题描述】:

首先让我说,我在 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;    
}

但这似乎很乏味,与 C 的精神背道而驰。更不用说它是穷人的 OO。

这个程序最终会变得相当大,所以从一个好的设计组织开始是至关重要的。我想随着 C 语言的多年发展,某些设计模式已经发展到如何最好地构建代码以实现可维护性。就像函数式编程一样,我希望过程式编程有一个干净且可读性强的范式。

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

【问题讨论】:

  • 我不想只选择一个答案,因为它们都有有用的花絮,但不透明指针参考可能是我不知道的最有用的东西。谢谢!

标签: c


【解决方案1】:

这是相当正常和明智的做法。但是尽量不要在头文件中暴露结构布局,这样你就可以灵活地实现它并更好地管理你的依赖关系。

更多详情请见Opaque pointer

【讨论】:

    【解决方案2】:

    您所建议的是我在做这种事情的日子里总是编写 C 程序的方式。我不认为这是“可怜的 OO”,我认为这是明智的程序化编程实践。

    我会观察一些关于您的 C 代码的事情:

    • 将 typedef 与结构定义一起使用,这样您就无需在整个代码中散布“struct”关键字
    • 仅在实际需要时才使用强制类型转换 - 对 malloc() 的返回值进行强制类型转换是不必要的

    【讨论】:

    • 好建议。我所说的“可怜的 OO”的意思是它是一个非常有限的 OO(即没有多态性、没有封装等)。
    • 但请注意 typedef 被某些人认为是不好的做法,包括 Linux 内核人员
    【解决方案3】:

    嗯...我们过去只使用命名约定... Ergo:str* 使用什么常见的数据结构?所以也许只需要 C# 语法和 s/./_/g?

    • foo_constructor
    • foo_destructor
    • foo_someMethod
    • foo_someMethod2 // 在 ANSI C 中不是没有重载
    • foo_otherMethod

    ...而且没有继承...

    • foo2_constructor
    • foo2_destructor
    • foo2_someMethod // 不存在多态性

    但是看好的一面......你可以使用指针到指针到指针到函数返回指针到指针int!哦,太高兴了!

    我最好的建议是学习 Java 的课程(并通过推理 C#)并构建您的库以不产生副作用...更多 typdefs == 减少头痛...如果您的锻炼如何遵循这位圣人建议请让我知道;-)

    干杯。基思。

    【讨论】:

    • 通过“副作用”,我假设您的意思是拥有静态变量、全局变量等?显然,这些库会对它们修改的“对象”产生副作用。
    • 一般情况下,您可以返回新状态而不是改变现有状态以更新某些状态,这符合函数式编程,并且将使数据流依赖关系更加明确和易于遵循。跨度>
    【解决方案4】:

    这是编写 C 程序的一种非常合理的方式。还有另一个大型应用程序,它的功能几乎相同——称为 Linux 内核。那里使用了一些几乎面向对象的功能:

    • 结构和结构上的操作用于封装,就像在您的示例中一样
    • 指向基结构的指针作为穷人继承的一种形式——你会发现大量的 对 struct kobject 的引用
    • 生成函数以替代模板编程的宏

    【讨论】:

      【解决方案5】:

      C 一直是一种低级语言,在这方面,根据您的代码功能和模块来组织您的数据结构将非常有用。

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

      【讨论】:

        【解决方案6】:

        我同意上述建议。你正在做最好的方式..如果你想用 C 编程。

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

        但我们在这里得到的是一个简单的 C++ 到 C 编译器。为什么不直接用 C++ 编程,使用真正的 C++ 编译器,使用干净的接口,然后将 C++ 代码与 C 代码链接起来?无论如何,您需要在 C 与 C++ 中进行编码的原因是什么?或者,如果您需要,从编译器生成 C 代码并将输出的 C 代码与您需要的任何其他代码一起编译。

        【讨论】:

        • 我真的不是 C++ 的粉丝,尽管它在过去几年里有了很大的改进(Boost 是一个很棒的库)。除此之外,这个项目的一部分是相当低级的,这是选择 C ​​的原因之一。另一个是它将是开源的,并希望尽可能地保持灵活性。我可以用 C++ 完成,但这会导致更多我认为值得的问题。
        • 你不需要使用所有的特性——只要坚持一个非常简单的子集——即类、方法、构造函数、析构函数——将其余的保留在标准 c 中。对于开源版本,您可以运行 C++ 到 C 编译器并分发 C 代码。
        • C是我们在底层做的,c++对Linux生态几乎没有价值。你要么做对了,用 C 慢慢来,或者你使用像 golang 这样的现代语言来处理你仍然想要完全编译的东西。 C++ 是代码的开发者,这与精神背道而驰,Linus 做对了。
        【解决方案7】:

        我已经在一个项目上工作了一段时间,其中库需要在 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 ();
        }
        

        如果有问题请见谅;写得有点快。

        【讨论】:

        • 是的,这就是我想要避免的。不过,我听说这基本上就是 Stroustrup 编写第一个 C++ 编译器要做的事情。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-07
        • 2022-01-07
        • 2011-08-23
        • 2018-07-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多