关于内联:C中的内联Setter和Getter函数

Inlined Setter and Getter functions in C

在C++中,在头文件中可以有一个声明为内联的吸收器函数:

1
2
3
4
5
6
7
8
class Cpp_Example
{
  public:
    unsigned int get_value(void)
    { return value;}
  private:
    unsigned int value;
};

通过包含这个头文件,客户机方法和函数可以使用getter函数来访问私有变量。

我希望用C语言来模拟这个概念:你好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef HELLO_H
#define HELLO_H
#include <stdio.h>

inline void Print_Hello(void)
{
    extern const char hello_text[32];
    puts(hello_text);
}


inline void Print_Value(void)
{
    extern unsigned int value;
    printf("Value is: %d
"
, value);
}

#endif // HELLO_H

你好,C:

1
2
3
4
const char hello_text[32] ="Hello World!
"
;

static unsigned int value = 5U;

主要内容:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <stdlib.h>

#include"hello.h"

int main(void)
{
    Print_Hello();
    Print_Value();
//  puts(hello_text);
    return EXIT_SUCCESS;
}

我从gcc得到一个链接器错误:

1
2
3
$ gcc -o main.exe main.c hello.c
/tmp/cc41ZB8H.o:main.c:(.rdata$.refptr.value[.refptr.value]+0x0): undefined reference to `value'
collect2: error: ld returned 1 exit status

有没有方法让内联函数(在头文件中)访问另一个翻译单元中的静态变量?

或者有实现内联getter函数的方法吗?

我在嵌入式平台上使用IAR嵌入式工作台、ARM7TDMI处理器。GCC编译器用于在PC上测试概念。

编辑1:背景我正在优化关键部分内的getter调用。目的是减少在关键部分花费的时间。

编辑2:无全局我们商店使用的编码准则没有规定全局变量。此外,该系统是一个运行微硅片的RTOS。


首先,与C++中有私有变量相同的方式,您可能意味着为EDCOX1 OR 2而不是全局变量拥有私有变量。有了这个假设,您可以使用一个模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* some_type.h */
struct some_type
{
    int public_data;
    void *privates;
};

struct some_type_privates
{
    char hello[32];
    int value;
};

inline const char *get_hello(struct some_type *t)
{
    struct some_type_privates *p = t->privates;
    return p->hello;
}

inline int get_value(struct some_type *t)
{
    struct some_type_privates *p = t->privates;
    return p->value;
}

/* similarly for setters */

与您的私有变量及其getter和setter在头文件中的方式相同,您也可以在C中这样做。

另一方面,我建议不要在C中尝试编码C++,而C++喜欢使事情复杂化很多,以防止白痴破坏某些东西,而C则相信程序员有一定程度的智力。这些假设是否合理不是讨论的问题。但我要说的是,C的精神不是隐藏一个变量,这样程序员就不会错误地访问它。

也就是说,这是您通常在C中生成结构的方式:

1
2
3
4
5
6
7
8
struct some_type
{
    int public_data;
    char hello[32];     /* read only */

    /* internal */
    int value;
};

(当然,有足够的文档)它告诉任何程序员,她不应该重写hello,但可以自由地阅读(您试图通过内联getter实现的)。它还表明value是私有的,因此程序员不应该读或写它。

您可以在许多接受或返回结构的POSIX函数中看到这一点。一些不需要控制访问的允许您自由地修改结构,例如stat。一些确实需要检查输入的具有setter,例如pthread_attr_*


您需要删除static关键字。static定义是编译单元的本地定义。


下面是我用来隐藏全局变量的模式。

在一些头文件(如module_prefix.h中),您声明以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef int value_t;  // Type of the variable

static inline value_t get_name(void)    __attribute__((always_inline));
static inline void    set_name(value_t) __attribute__((always_inline));

static inline value_t get_name(void) {
    extern value_t module_prefix_name;
    return module_prefix_name;
}

static inline void set_name(value_t new_value) {
    extern value_t module_prefix_name;
    module_prefix_name = new_value;
}
/* Note that module_prefix_name is *no longer* in scope here. */

当然,您必须在一些编译单元中定义module_prefix_name,而不使用static关键字,如上所述,例如在module_prefix.c中,您有以下内容:

1
2
#include"module_prefix.h"
value_t module_prefix_name = MODULE_PREFIX_NAME_INIT_VALUE;

这与Thomas Matthews试图使用的模式基本相同,深入了解其本质,并确保编译器始终在函数中输入,并且不会不必要地生成显式函数体。注意使用module_prefix作为穷人的姓名空间。


假设您的意思是全局的静态分配变量,您可以这样做:

例如:H:

1
2
3
4
#ifndef Example
#define Example
  extern int getValue();
#endif

例如,C

1
2
3
4
5
6
7
8
9
#include"Example.h"

static int value;

inline int getValue() {
    return value;
}

// All the functions in Example.c have read/write access

在用值例如.c

1
2
3
4
5
6
7
#include"Example.h"

// All the functions in UsesValueExample.c have read-only access

void printValue() {
    printf("value = %d", getValue());
}

如果您想要花哨并强制所有代码通过getter和setter访问,例如,如果变量是易失性的,并且您希望大力鼓励所有方法使用变量的本地缓存以避免访问易失性的开销,那么:

例如,在挥发物中:

1
2
3
4
#ifndef VolatileExample
#define VolatileExample
  extern int getValue();
#endif

在挥发物中例如.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include"VolatileExample.h"

void setValue(); // Forward declaration to give write access

// All the functions in VolatileExample.c have read/write access via getters and setters

void addToValuesAndIncrementValue(int const values[], int const numValues) {
    int value = getValue(); // Cache a local copy for fast access

    // Do stuff with value
    for (int i = 0; i < numValues; i++) {
        values[i] += value;
    }
    value++;

    // Write the cache out if it has changed
    setValue(value);
}

// Put the definitions after the other functions so that direct access is denied

static volatile int value;

inline int getValue() {
    return value;
}

inline void setValue(int const newValue) {
    value = newValue;
}

在用volatilevalueexample.c

1
2
3
4
5
6
7
#include"VolatileExample.h"

// All the functions in UsesVolatileValueExample.c have read-only access

void printValue() {
    printf("value = %d", getValue());
}


正如沙巴所写,它在C语言中并不真正起作用。关键字inline意味着静态的,即使编译器实际上没有将其inline。如果它是一个如此短的函数,它可能会内联它。但关键是,如果它不是静态的,它甚至不能考虑将它内联,因为函数需要在外部可见,它需要一个地址,而内联函数没有这个地址。因为它在您的编译单元中是本地的,所以它只能处理该编译单元内已知的内容。因此,你需要说一些关于这个值变量,就像你也需要在C++头中提到它一样,只有在C中没有私有的东西。你不能在同一种情况下进行数据隐藏和数据隐藏,既不在C中,也不在C++中。