有什么方法可以保护变量在运行时在 C 中被修改吗?

Is there any way of protecting a variable for being modified at runtime in C?

我想知道是否有任何方法可以保护变量在初始化后不被修改(类似于 "constantize" 运行时的变量)。例如:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int v, op;
    scanf( "%d", &op );
    if( op == 0 )
        v = 1;
    else
        v = 2;
// here transform v to a constant...
    .
    .
// ...and that any attempt to modify v yields to an error.
    .
    .
    return EXIT_SUCCESS;
}

是:考虑您的代码:

foo.h:

void do_something(int arg);

foo.c:

#include "foo.h"

void do_something(int arg)
{
    // implement
    //
    // Here "arg" is completely under your control.
}

foo_test.c:

#include "foo.h"

// add unit tests for do_something

main.c:

#include <stdio.h>
#include <stdlib.h>
#include "foo.h"

int main(void)
{
    int op;
    if (scanf("%d", &op) != 1) { abort(); }

    do_something(op == 0 ? 1 : 2);
}

现在从代码中完全清楚 do_something 的函数参数是函数的私有和局部函数,不受调用之上的任何影响。

不,从来没有。

您可以做到 const,但这更像是一个轻微的提示,几乎不费吹灰之力就可以摆脱。此外,如果您有指向某物的指针,您可以随时通过直接内存访问来更改它。

您也可以将它隐藏在管理对它的写访问的 class 中,但您处于与第一种情况相同的情况 - 您有一个指向它的指针。

防止全局变量在初始化后被修改的唯一方法是声明它const:

const int i = 5;

但是,如上所示,这需要使用定义对其进行初始化。除了在编译时计算的 常量表达式 之外,无法从程序代码或使用其他方式对其进行初始化。

请注意,虽然您 可以 放弃常量,但这会导致 未定义的行为 并且很可能会导致问题 const 变量可能会被放入程序的只读内存区域。

如果你需要对这样一个变量的访问控制,你必须把它作为static放入一个函数(在第一次调用时初始化),或者 - 更好的是单独的 module/compilation 单元(也作为 static)。然后在此使用显式 setter/getter 函数:

"wrapper.h":

#ifndef WRAPPER_H
#define WRAPPER_H

extern void set_once(int v);
extern int get_value(void);

#endif

"wrapper.c":

#include <stdbool.h>
#include "wrapper.h"

static struct {
    bool is_set;    // guaranteed false on startup
    int value;
} my_var;

void set_once(int v)
{
    if ( !my_var.is_set )
        my_var.value = v;
    else
        ; // report an error, e.g. abort()
}

int get_value(void)
{
    if ( !my_var.is_set )
        return my_var.value;
    // report an error, e.g. abort()
}

"main.c"

#include "wrapper.h"

int main(void)
{
    set_once(5);
    int i = get_value();
}

这样,如果您使用未初始化的值或尝试多次设置它,您将遇到运行时错误。请注意,该标志依赖于初始化为 0 的全局变量(保证计算 false)。 尽管您可能只是忽略多个集合,但至少在 debugging/testing 期间(例如使用 assert)捕获和报告是一种很好的做法。

编辑:

上面的方法是针对全局变量的。如果要保护多个变量,则可以对其进行修改,例如函数采用指向结构的指针。如果要使用不同的类型,将标志打包到它自己的结构中,并将其作为第一个匿名字段添加到每个要保护的类型的一个结构类型中。如果 gcc 扩展可用并被允许,请查看 -fplan9-extensions。使用不透明指针可以避免意外的外部修改。

但是,对于局部变量,请使用@MattMcNabb 的版本。

您可以像这样使输入的结果const

int func()
{
    int op = 0;
    scanf( "%d", &op );
    if( op == 0 )
        return 1;
    else
        return 2;
}

int main()
{
    const int v = func();
    // ...
}

注意。当然,没有办法阻止未定义的行为在程序中发生,它似乎发生了变化v(因为根据定义,未定义的行为可以产生任何影响)。