使C模块变量以只读方式访问

使C模块变量以只读方式访问,c,readonly,C,Readonly,我想给一个模块变量一个客户端模块的只读访问权限。 几种解决方案: 1。最常见的是: // module_a.c static int a; int get_a(void) { return a; } // module_a.h int get_a(void); 这使得每个变量共享一个函数,一个函数调用(我考虑的是执行时间和可读性),每次读取一个副本。假设没有优化链接器 2。另一个解决方案: // module_a.c static int _a; const int * const

我想给一个模块变量一个客户端模块的只读访问权限。 几种解决方案:

1。最常见的是:

// module_a.c
static int a;

int get_a(void)
{
    return a;
}

// module_a.h
int get_a(void);
这使得每个变量共享一个函数,一个函数调用(我考虑的是执行时间和可读性),每次读取一个副本。假设没有优化链接器

2。另一个解决方案:

// module_a.c
static int _a;
const int * const a = &_a;

// module_a.h
extern const int * const a;

// client_module.c
int read_variable = *a;
*a = 5;  // error: variable is read-only
我喜欢这样,除了客户端需要读取指针的内容这一事实之外。此外,每个只读变量都需要其
extern const
指针指向
const

3。第三种解决方案(受第二种方案启发)是将变量隐藏在结构和指向结构的外部指针后面。在我看来,在客户机模块中,符号
module\u name->a
更具可读性

4。我可以为
get_a(void)
函数创建一个内联定义。它看起来仍然像客户端模块中的函数调用,但是应该进行优化

我的问题是:

  • 有没有最好的方法使在模块中修改的变量在其他模块中以只读方式访问?哪方面最好

  • 您会接受或拒绝使用上述哪些解决方案,为什么


我知道这是微优化——我可能不会实现它——但我仍然对这种可能性感兴趣,最重要的是了解情况。

关于选项4,如果变量在实现文件之外无法访问,我不确定您是否可以将其内联。我不认为选项2和选项3是真正的只读。指针可以丢弃常量并进行修改(const只是一个编译器“警告”,没有具体内容)。只有选项#1是只读的,因为它返回一个副本。

对于与变量访问相同的速度,您可以在内联函数中定义一个外部变量:

static inline int get_a(void)
{
    extern int a_var;
    return a_var;
}
这是简单明了的。其他选择似乎不必要地复杂

编辑:我假设你的名字使用前缀,因为你写的是C。所以它实际上是:

extern int my_project_a;
这可以防止客户端意外地使用相同的名称创建变量。但是,如果客户机故意使用相同的名称创建变量,该怎么办?在这种情况下,你已经输了,因为客户要么1)积极地试图破坏你的图书馆,要么2)无法胜任超出合理住宿范围的工作。在情况1中,您无法阻止程序员。在第二种情况下,程序无论如何都会被破坏

尝试在您的系统上运行
nm/lib/libc.so
或等效程序。您将看到,大多数
libc
实现都有几个未在头文件中定义的变量。在我的系统中,这包括像
\uuuuuuhostubyaddr\ucache
这样的东西。照顾我并阻止我运行不是C库实现者的责任:

extern void *__host_byaddr_cache;
__host_byaddr_cache = NULL;
如果你一开始就认为你必须强迫客户将你的变量视为只读变量,那么你就走上了一条毫无结果的偏执之路。
static
关键字实际上只是为了方便将对象排除在全局名称空间之外,它不是也从来不是防止外部访问的安全措施

强制只读变量的唯一方法是管理客户机代码-将其沙箱化到VM中,或者通过算法验证它不能修改您的变量

  • 最常见的是:
  • 这是最常见的一个原因。这是最好的


    我认为在大多数情况下,性能受到的影响不足以值得担心。

    为什么在第二个建议中使用volatile?我自己也差点问到这一点。我在想,如果
    \u a
    在中断时被修改(这是从测试代码中导入的),但这与问题无关,所以我将删除它。如果您的用户正在丢弃您的
    常量
    ,那么他们为什么不也通过扫描调试器的符号表来查看您的
    静态
    变量呢?C中没有“具体的”只读。我完全同意这个答案,#1是在C中进行私有封装的正确方法。我不会太担心内联,在大多数程序中,内联只是一个预先成熟的优化。而且在>99%的应用程序中,您不需要具有如此高的实时性能,以至于内联节省的少量CPU时间实际上很重要。我只使用嵌入式实时系统,在我的职业生涯中,我只能提出一个实际需要使用内联的案例。所以,如果你只是做一些随意的桌面编程,忘记你曾经听说过内联。我同意Ioan#1是最好的方法,因为它允许您更改有关只读变量的实现细节,同时保持与客户端的向后兼容性。@Lundin-我见过内联函数显著提高整个程序速度(500%或更多)的情况。但是我对
    inline
    关键字的工作原理没有任何错觉。我使用它的原因是,访问器函数非常小,可以放入头文件,而不会生成任何编译器警告或链接器错误。然后,编译器可以选择内联或不内联函数。@Dietrich应该注意的是,编译器可以自由内联或不内联,无论关键字是否存在。当然,内联将导致更快的程序,特别是在有大量搜索和排序的情况下(在实时系统中通常不是这样)。但是,没有人需要优化速度。如果程序速度提高了500%,但对规范或用户没有影响,那么您将一无所获。此外,内联将大大增加程序的大小,这可能是一个问题。没有一般的对错,都是针对具体项目的