简体   繁体   English

C结构的良好编码实践?

[英]Good Coding Practice With C structs?

In C, you can define structures to hold an assortment of variables; 在C中,您可以定义结构来保存各种变量;

typedef struct {
    float       sp;
    float       K;                 // interactive form - for display only
    float       Ti;                //  values are based in seconds
    float       Td;
} pid_data_t;

But lets say that K , Ti , and Td should never be set publicly, and should only be used for storing the values after they have been manipulated. 但是我们可以说KTiTd永远不应该公开设置,并且只应该用于在操作后存储值。 So, I want these values not to be updated by; 所以,我希望这些值不被更新;

pid_data_t = pid_data;
pid_data.K = 10;         // no good! changing K should be done via a function

I want them to be set via a function; 我想通过一个函数设置它们;

int8_t pid_set_pid_params(float new_K_dash, float new_Ti_dash, 
    float new_Td_dash)
{
    …                             // perform lots of things
    pid_data->K  = new_K_dash;
    pid_data->Ti = new_Ti_dash;
    pid_data->Td = new_Td_dash;
}

Any thoughts on this? 有什么想法吗? I know C++ uses like a get/set property, but was wondering what people might do on C. 我知道C ++使用类似于get / set属性,但是想知道人们可能在C上做什么。

Your public interface should only offer an opaque pointer (maybe DATA* , or data_handle ), as well as handler functions create_data() , set_data_value() , read_data_value() , free_data() , etc., which operate on the opaque pointer. 您的公共接口应该只提供不透明指针(可能是DATA*data_handle ),以及处理器函数create_data()set_data_value()read_data_value()free_data()等,它们对不透明指针进行操作。

Much like FILE* . 很像FILE*

Just don't give your clients the internal header files :-) 只是不要给你的客户端内部头文件:-)

// library.h

typedef struct data_t * data_handle;

data_handle create_data();
void        free_data(data_handle);

Private implementation (don't ship): 私人实施(不发货):

#include "library.h"

struct data_t
{
  /* ... */
};

data_handle create_data() { return malloc(sizeof(struct data_t)); }
void        free_data(data_handle h) { free(h); }
/* etc. etc. */

The canonical way to do this is by using a combination of opaque pointers and public structs, along with allocators, getters and setters for the private elements. 执行此操作的规范方法是使用不透明指针和公共结构的组合,以及私有元素的分配器,getter和setter。 About along these lines: 关于这些方面:

foo.h foo.h中

typedef struct Foo {
    /* public elements */
} Foo;

Foo *new_Foo(void);
void Foo_something_opaque(Foo* foo);

foo.c foo.c的

#include "foo.h"

typedef struct Private_Foo_ {
    struct Foo foo;
    /* private elements */
} Private_Foo_;

Foo *new_Foo(void)
{
    Private_Foo_ *foo = malloc(sizeof(Private_Foo_));
    /* initialize private and public elements */
    return (Foo*) foo;
}

void Foo_something_opaque(Foo *foo)
{
    Private_Foo_ *priv_foo = (Private_Foo_*) foo;
    /* do something */
}

This woks, because C guarantees, that the address of a struct variable always is equal to the address of the very first struct element. 因为C保证,结构变量的地址总是等于第一个struct元素的地址。 We can use this to have a Private_Foo_ struct, containing a public Foo at the beginning, giving out pointers to the whole thing, with the compilation units not having access to the Private_Foo_ struct defintion just seeing some memory without any context. 我们可以使用它来创建一个Private_Foo_结构,在开头包含一个公共Foo,给出指向整个事物的指针,编译单元无法访问Private_Foo_ struct定义,只看到一些没有任何上下文的内存。

It should be noted that C++ works quite similar behind the curtains. 应该注意的是,C ++在幕后的工作方式非常相似。

Update 更新

As KereekSB pointed out, this will break if used in a array. 正如KereekSB指出的那样,如果在数组中使用,这将会中断。

I say: Then don't make Foo f[] , however tempting, but make an arrays of pointers to Foo: Foo *f[] . 我说:然后不要制作Foo f[] ,无论多么诱人,但要制作一个指向Foo的指针数组: Foo *f[]

If one really insists on using it in arrays do the following: 如果真的坚持在数组中使用它,请执行以下操作:

foo_private.h foo_private.h

typedef struct Private_Foo_ {
    /* private elements */
} Private_Foo_;

static size_t Private_Foo_sizeof(void) { return sizeof(Private_Foo_); }

foo_private.h is written in a way, that it can be compiled into an object file. foo_private.h是以某种方式编写的,它可以编译成目标文件。 Use some helper program to link it and use the result of Private_Foo_sizeof() to generate the actual, plattform dependent foo.h from some foo.h.in file. 使用一些帮助程序来链接它并使用Private_Foo_sizeof()的结果从一些foo.h.in文件生成实际的,与平台相关的foo.h。

foo.h foo.h中

#include

#define FOO_SIZEOF_PRIVATE_ELEMENTS <generated by preconfigure step>

typedef struct Foo_ {
    /* public elements */
    char reserved[FOO_SIZEOF_PRIVATE_ELEMENTS];
} Foo;

Foo *new_Foo(void);
void Foo_something_opaque(Foo* foo);

foo.c foo.c的

#include "foo.h"
#include "foo_private.h"

Foo *new_Foo(void)
{
    Foo *foo = malloc(sizeof(Foo));
    /* initialize private and public elements */
    return (Foo*) foo;
}

void Foo_something_opaque(Foo *foo)
{
    Private_Foo_ *priv_foo = (Private_Foo_*) foo.reserved;
    /* do something */
}

IMHO this is really messy. 恕我直言这真是一团糟。 Now I'm a fan of smart containers (unfortunately there's no standard container library for C). 现在我是智能容器的粉丝(遗憾的是,C没有标准的容器库)。 Anyway: In such a container is creates through a function like 无论如何:在这样的容器中通过类似的功能创建

Array *array_alloc(size_t sizeofElement, unsigned int elements);
void *array_at(Array *array, unsigned int index);
/* and all the other functions expected of arrays */

See the libowfaw for an example of such an implementation. 有关此类实现的示例,请参阅libowfaw。 Now for the type Foo it was trivial to provide a function 现在对于Foo类型来说,提供一个函数是微不足道的

Array *Foo_array(unsigned int count);

in C, by convention.... 在C,按照惯例......

for OO C like this... 像这样的OO C ......

I'd have a pid_data_create(&data) // initializes your struct 我有一个pid_data_create(&data) // initializes your struct

and pid_data_set_proportional_gain(&data, 0.1); pid_data_set_proportional_gain(&data, 0.1);

etc... 等等...

so basically achieving a C++ ish class... prefix all functions with the "class" / "struct" name and always pass the struct * as the first parameter. 所以基本上实现了一个C ++ ish class ...前缀所有带有“class”/“struct”名称的函数,并且总是将struct *作为第一个参数传递。

also, it should store function pointers for polymorphisim, and you shouldn't call those function pointers directly, again, have a function that takes your struct as a parameter, and then the can make the function pointer call (can check for nulls, fake inheritance/virtual functions, and other stuff) 此外,它应该存储多态性的函数指针,你不应该直接调用那些函数指针,再次,有一个函数将你的struct作为参数,然后可以调用函数指针(可以检查空值,假继承/虚函数,等等)

Object orientation is a way of thinking and modelling, data encapsulation where struct data should not be modified directly by the user can be implemented this way: 面向对象是一种思考和建模的方式,用户不能直接修改struct数据的数据封装可以这样实现:

my_library.h my_library.h

#ifndef __MY_LIBRARY__
#define __MY_LIBRARY__
typedef void MiObject;

MyObject* newMyObject();

void destroyMyObject(MyObject*)

int setMyObjectProperty1(MyObject*,someDataType1*);

/*Return a pointer to the data/object,  classic pass by value */
someDataType1* getMyObjectProperty2Style1(MyObject*);

int setMyObjectProperty2(MyObject*,someDataType2*);

/* The data/object is passed through reference */
int getMyObjectProperty2Style2(MyObject*,someDataType2**);

    /* Some more functions here */
#endif

my_library.c my_library.c

struct _MyHiddenDataType{
    int a;
    char* b;
    ..
    ..
};

MyObject* newMyObject(){
struct _MyHiddenData* newData = (struct _MyHiddenData*)malloc(sizeof(struct _MyHiddenData);
//check null, etc
//initialize data, etc
return (MyObject*)newData;
}

int setMyObjectProperty1(MyObject* object,someDataType1* somedata){
    struct _MyHiddenData* data = (struct _MyHiddenData*)object;
    //check for nulls, and process somedata
    data->somePropery=somedata;
}

someDataType1* getMyObjectProperty2Style1(MyObject*){
    struct _MyHiddenData* data = (struct _MyHiddenData*)object;
    //check for nulls, and process somedata
    return data->someProperty;
}
/* Similar code for the rest */

And this way you have encapsulated the struct properties as if they were private. 通过这种方式,您将struct属性封装为私有。 On the same manner static functions inside my_libray.c would behave as private functions. 以同样的方式,my_libray.c中的静态函数将表现为私有函数。 Get a good look at C and you'll see, that your imagination is the limit to what you can do. 好好看看C,你会发现,你的想象力是你能做的极限。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM