C语言能否决定指针指向的内存是否可以访问?

C语言能否决定指针指向的内存是否可以访问?,c,pointers,C,Pointers,例如 如果我有一个指针 int* p; p = (int*)2; // just for test *p = 3; // it will be crack, right? 通常情况下,值为2的指针的访问将被中断。但实际上裂缝并不是那么简单。指针的无效值可能来自运行时错误。我想找到一种方法在访问指针之前检查它。在标准C99中,这(在*p=3;语句中的(int*)2是(UB)。读一下。你应该。这就是为什么用C语言编程如此困难的原因(其他编程语言,如Ocaml、Common Lisp的UB要少得多)

例如

如果我有一个指针

int* p;
p = (int*)2; // just for test
*p = 3; // it will be crack, right?
通常情况下,值为2的指针的访问将被中断。但实际上裂缝并不是那么简单。指针的无效值可能来自运行时错误。我想找到一种方法在访问指针之前检查它。

在标准C99中,这(在
*p=3;
语句中的
(int*)2
是(UB)。读一下。你应该。这就是为什么用C语言编程如此困难的原因(其他编程语言,如Ocaml、Common Lisp的UB要少得多)

C程序可能有未定义的行为,但可能并不总是崩溃

实际上,在用C编写代码时,要小心指针。显式初始化它们(通常为
NULL
)。对指针运算要非常小心。避免和。可能有帮助(例如)但有限(阅读&)。您可以在运行时经常使用和检查指针和索引

在一些嵌入式独立C实现(例如,为类似设备编码)上,一些地址可能具有特定含义(例如,是一些物理IO设备),因此UB可能非常可怕

(下面我将重点介绍Linux)

在某些实现和某些操作系统上,您可能会测试地址是否有效。例如,在Linux上,您可以解析
/proc/self/maps
来计算某个给定地址是否有效(有关
/proc/
的更多信息,请参阅)

(因此,您可以在Linux上编写一些函数
bool isreadableaddress(void*)
,该函数将解析
/proc/self/maps
,并告诉您的系统中的地址是否可读;但由于需要几个地址,因此效率不高)

您应该使用和编译所有警告和调试选项(
gcc-Wall-Wextra-g
),并使用调试器(
gdb
)和一些类似于
-fsanize=address

您可能会处理
SIGSEGV
信号,但这是一个非常复杂且高度不可移植的信号(操作系统、处理器和特定的)。除非你是一位大师,否则你甚至不应该尝试。

是的,“它将是裂纹”

您的程序无法知道任意初始化的指针在运行时是否实际“工作”。首先,在运行代码之前先编译代码,可能在完全不同的计算机上运行。编译器无法预测未来

该语言处理这个问题的方式是,只要您希望程序具有定义良好的行为,任何未显式指向您在程序中创建的对象或数组的指针都不能存在


基本上,唯一可以确定的方法就是不要这样做。

实际上这是可能的。。。有点

不是普通的C语言,但大多数环境允许您测试是否可以写入指针

不幸的是,您无法知道指针是否指向您想要的内容。这意味着你可以指向另一个与你期望的不同的有效地址,无意中破坏了你自己的一段记忆

char a[2];
int b; // assuming they are stored on the stack sequentially and aligned one right after the other...

char *ptr = (char*)a;

ptr += 3;

*ptr = 'b' // valid pointer, but probably an error....

无法检查指针在C中是否有效。访问无效内存也不能保证抛出错误。不过,OP似乎在询问是否可以检查指针。请注意,在Windows上,有些函数似乎完全按照OP的要求执行(IsBadReadPtr等)。不要使用它们:(标题是“IsBadXXXPtr真的应该被称为crashprogrammandomy”)。可能有人比那篇文章的作者更了解Windows,但我不想打赌。每个windows程序员都应该阅读该博客。这如何回答取消引用
(int*)2
?此外,Martin Bonner评论(我的答案)并引用了一些基本上不鼓励在Windows上使用
IsBadWritePtr
的内容……你读过他的文章标题了吗?他不在乎
(int*)2
。。。这只是一个例子。。。我试图用简单的术语解释为什么他所要求的基本上是不可能的。在Linux上,可以(通过
/proc/self/maps
)判断给定的地址是否可读。但你的论点适用。有效地址可能不会指向预期的内容。酷:-)。还有一些字符
*ptr='b'
不是有效的指针。它可能会崩溃,也可能不会崩溃。例如,
a
可能正好位于堆栈上的返回地址之前,如果在valgrind下执行,它可能会停止程序。