有没有办法保护变量在C中在运行时被修改?
我想知道是否有任何方法可以保护变量一旦被初始化就被修改(比如在运行时“变量”变量“)。 例如:
#include #include 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; }
你可以使输入的结果像这样:
int func() { int op = 0; scanf( "%d", &op ); if( op == 0 ) return 1; else return 2; } int main() { const int v = func(); // ... }
NB。 当然,没有办法防止稍后在程序中发生未定义的行为,这似乎会改变v
(因为根据定义,未定义的行为可能会产生任何影响)。
是的:考虑您的代码:
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 #include #include "foo.h" int main(void) { int op; if (scanf("%d", &op) != 1) { abort(); } do_something(op == 0 ? 1 : 2); }
从代码中可以清楚地看出, do_something
的函数参数是函数的私有函数和本地函数,并且不受调用之上任何内容的影响。
在初始化之后防止全局变量被修改的唯一方法是声明它为const
:
const int i = 5;
但是,如上所示,这需要用定义初始化。 无法从程序代码初始化它或使用在编译时计算的常量表达式以外的其他方法。
请注意,虽然你可以抛弃const,但这会导致未定义的bahaviour并且很可能导致问题,因为const
变量可能被放入程序的只读存储区。
如果确实需要对这样的变量进行访问控制,则必须将其作为static
放入函数中(在第一次调用时初始化),或者 – 更好的单独模块/编译单元(也作为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 #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, eg abort() } int get_value(void) { if ( !my_var.is_set ) return my_var.value; // report an error, eg abort() }
"main.c" #include "wrapper.h" int main(void) { set_once(5); int i = get_value(); }
这样,如果您使用未初始化的值或尝试多次设置它,您将收到运行时错误。 请注意,该标志依赖于全局变量初始化为0(保证评估为false
)。 虽然您可能只是忽略多个集合,但最好是捕获和报告,至少在调试/测试期间(例如使用assert
)。
编辑:
上述方法适用于全局变量。 如果要保护多个变量,可以对其进行修改,例如函数采用指向结构的指针。 如果要使用不同的类型,请将标志打包到其自己的结构中,并将其作为第一个匿名字段添加到每个要保护的类型的结构类型中。 如果gcc-extensions可用且允许,请查看-fplan9-extensions
。 使用不透明指针可以避免意外的外部修改。
但是,对于局部变量,请使用@ MattMcNabb的版本。
没有永不。
你可以把它变成const
,但这更像是一个轻微的暗示,可以毫不费力地抛弃它。 此外,如果你有一个指针,你可以随时通过直接内存访问来改变它。
您也可以将其隐藏在管理对它的写访问权的类中,但是您遇到的情况与第一种情况相同 – 您有指向它的指针。