在C中编写代码时,常见的情况是编写返回指针的函数。如果在运行时编写的函数中发生了某些错误,则可以返回NULL
以指示错误。NULL
只是特殊的内存地址0x0,它从来不用于任何东西,只用于表示特殊情况的出现。
我的问题是,还有什么其他特殊的内存地址永远不会用于用户应用程序数据?
我之所以想知道这一点,是因为它可以有效地用于错误处理。考虑到这一点:
#include <stdlib.h>
#include <stdio.h>
#define ERROR_NULL 0x0
#define ERROR_ZERO 0x1
int *example(int *a) {
if (*a < 0)
return ERROR_NULL;
if (*a == 0)
return (void *) ERROR_ZERO;
return a;
}
int main(int argc, char **argv) {
if (argc != 2) return -1;
int *result;
int a = atoi(argv[1]);
switch ((int) (result = example(&a))) {
case ERROR_NULL:
printf("Below zero!\n");
break;
case ERROR_ZERO:
printf("Is zero!\n");
break;
default:
printf("Is %d!\n", *result);
break;
}
return 0;
}
了解一些用户应用程序永远不会使用的特定地址范围,可以有效地用于更高效和更干净的条件处理。如果你知道这一点,它适用于哪些平台?
我想跨度应该是特定于操作系统的。我对Linux很感兴趣,但是很高兴知道OS,Windows,Android和其他系统。
发布于 2013-03-05 19:22:11
答案在很大程度上取决于您的C编译器,以及您的CPU和操作系统,编译后的C程序将在哪里运行。
用户应用程序通常永远无法通过指向操作系统内核数据和代码的指针访问数据或代码。而操作系统通常不会将这些指针返回给应用程序。
通常,它们也永远不会得到指向没有物理内存备份的位置的指针。您只能通过错误(代码错误)或故意构造这样的指针来获得这样的指针。
C标准没有定义指针的有效范围,在C中,有效指针要么是NULL
指针,要么是指向生命尚未结束的对象的指针,它们可以是全局变量和局部变量,也可以是在malloc()'d
内存和函数中创建的变量。操作系统可以通过返回以下内容来扩展此范围:
malloc()
/free()
,并且需要使用特定于操作系统的适当函数来释放这个内存)NULL
,并且您的ERROR_ZERO
是可能的候选指针)我通常不鼓励在程序中使用硬编码和魔法指针。
如果出于某种原因,指针是通信错误条件的唯一方法,并且有多个错误条件,则可以这样做:
char ErrorVars[5] = { 0 };
void* ErrorPointer1 = &ErrorVars[0];
void* ErrorPointer2 = &ErrorVars[1];
...
void* ErrorPointer5 = &ErrorVars[4];
然后,您可以在不同的错误条件下通过ErrorPointer1
返回ErrorPointer1
,然后将返回的值与它们进行比较。不过这里有个警告。在法律上,不能使用>
、>=
、<
、<=
将返回的指针与任意指针进行比较。只有当两个指针指向或指向同一个对象时,这才是合法的。所以,如果你想要这样的快速检查:
if ((char*)(p = myFunction()) >= (char*)ErrorPointer1 &&
(char*)p <= (char*)ErrorPointer5)
{
// handle the error
}
else
{
// success, do something else
}
只有当p
等于这5个错误指针之一时,它才是合法的。如果不是,您的程序就可以合法地以任何可想象和不可想象的方式运行(这是因为C标准这样说)。为了避免这种情况,您必须将指针与每个错误指针分别进行比较:
if ((p = myFunction()) == ErrorPointer1)
HandleError1();
else if (p == ErrorPointer2)
HandleError2();
else if (p == ErrorPointer3)
HandleError3();
...
else if (p == ErrorPointer5)
HandleError5();
else
DoSomethingElse();
同样,指针是什么及其表示形式,是编译器和OS/CPU特有的。C标准本身不要求任何有效和无效指针的特定表示或范围,只要这些指针按照C标准的规定工作(例如,指针算法与它们一起工作)。有一个关于这个题目的好问题。
因此,如果您的目标是编写可移植的C代码,则不要使用硬编码和“魔术”指针,而更愿意使用其他方法来交流错误条件。
发布于 2013-03-05 16:07:28
NULL只是特殊的内存地址0x0,它从来不用于任何东西,只用于表示特殊情况的出现。
这并不完全正确:有些计算机内部的NULL
指针不是零(链接)。
是否有任何其他特殊的内存地址永远不会用于用户的应用程序?
即使是NULL
也不是通用的;没有其他通用未使用的内存地址,考虑到在C语言中可编程的不同平台的数量,这并不令人惊讶。
但是,没有人阻止您在内存中定义自己的特殊地址,将其设置为全局变量,并将其视为错误指示符。这将适用于所有平台,并且不需要特殊的地址位置。
在标题中:
extern void* ERROR_ADDRESS;
在C文件中:
static int UNUSED;
void *ERROR_ADDRESS = &UNUSED;
此时,ERROR_ADDRESS
指向一个全局唯一的位置(即UNUSED
的位置,它是定义它的编译单元的本地位置),您可以使用它来测试指针是否相等。
发布于 2013-03-05 16:08:52
它完全依赖于计算机和操作系统。例如,在内存映射IO的计算机上,例如“Game前进”,您可能不想将“左上角像素是什么颜色”的地址与用户数据混淆:
https://stackoverflow.com/questions/15236562
复制相似问题