各种平台上的指针地址范围 [英] Pointer address span on various platforms

查看:122
本文介绍了各种平台上的指针地址范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C语言中进行编码的一种常见情况是编写返回指针的函数.如果在运行时在编写的函数中发生了某些错误,则可能会返回NULL来指示错误. NULL只是特殊的内存地址0x0,它只用于表示特殊情况的发生而已.

A common situation while coding in C is to be writing functions which return pointers. In case some error occurred within the written function during runtime, NULL may be returned to indicate an error. NULL is just the special memory address 0x0, which is never used for anything but to indicate the occurrence of a special condition.

我的问题是,还有其他特殊的内存地址永远不会用于用户态应用程序数据吗?

我想知道的原因是因为它可以有效地用于错误处理.考虑一下:

The reason I want to know this is because it could effectively be used for error handling. Consider this:

#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;
}

了解一些特殊的地址范围,这些地址范围将永远不会被用户级应用程序使用,可以有效地用于更有效和更清洁的条件处理.如果您知道这一点,它适用于哪些平台?

Knowing some special span of addresses which never will be used by userland applications could effectively be utilized for more efficient and cleaner condition handling. If you know about this, for which platforms does it apply?

我猜跨度将是特定于操作系统的.我对Linux最感兴趣,但是对于OS X,Windows,Android和其他系统也很高兴.

I guess spans would be operating system specific. I'm mostly interested in Linux, but it would be nice to know for OS X, Windows, Android and other systems as well.

推荐答案

答案很大程度上取决于您的C编译器以及您要在其上运行已编译的C程序的CPU和OS.

The answer depends a lot on your C compiler and on your CPU and OS, where your compiled C program is going to run.

您的用户态应用程序通常将永远无法通过指向OS内核数据和代码的指针来访问数据或代码.而且操作系统通常不会将此类指针返回给应用程序.

Your userland applications typically will never be able to access data or code through pointers pointing to the OS kernel data and code. And the OS usually does not return such pointers to applications.

通常,它们也永远不会获得指向未由物理内存备份的位置的指针.您只能通过错误(代码错误)或有意构造此类指针来获取此类指针.

Typically they will also never get a pointer pointing to a location that's not backed up by physical memory. You can only get such pointers through an error (a code bug) or by purposefully constructing such a pointer.

C标准不以任何方式定义指针的有效范围是和不是.在C语言中,有效的指针可以是NULL指针,也可以是指向寿命尚未结束的对象的指针,这些指针可以是您的全局变量和局部变量,以及可以在malloc()'d内存和函数中创建的变量.操作系统可以通过返回以下内容来扩展此范围:

The C standard does not anyhow define what a valid range for pointers is and isn't. In C valid pointers are either NULL pointers or pointers to objects whose lifetime hasn't ended yet and those can be your global and local variables and those created in malloc()'d memory and functions. The OS may extend this range by returning:

  • 指向在C程序中未在源代码级别明确定义的代码或数据对象的指针(操作系统可能允许应用程序直接访问其某些代码或数据,但这并不常见,或者操作系统可能允许应用程序访问其中的某些代码或数据)它们的部分要么由应用程序在加载时由操作系统创建,要么在应用程序编译时由编译器创建.例如,Windows允许应用程序检查其可执行的PE映像,您可以询问Windows映像在内存中从何处开始.
  • 指向操作系统为应用程序/代表应用程序分配的数据缓冲区的指针(通常情况下,操作系统将使用自己的API,而不是应用程序的malloc()/free(),因此您需要使用适当的特定于操作系统的功能来释放此内存)
  • 特定于操作系统的指针,该指针不能被取消引用,而只能用作错误指示符(例如,您可能拥有多个像NULL这样的不可理解的指针,而您的ERROR_ZERO是可能的候选对象)
  • pointers to code or data objects not explicitly defined in your C program at its source code level (the OS may let apps access some of its code or data directly, but this is uncommon, or the OS may let apps access some of their parts that are either created by the OS when the app loads or created by the compiler when the app was compiled, one example would be Windows letting apps examine their executable PE image, you can ask Windows where the image starts in the memory)
  • pointers to data buffers allocated by the OS for/on behalf of apps (here, usually, the OS would use its own APIs and not your app's malloc()/free(), and you'd be required to use the appropriate OS-specific function to release this memory)
  • OS-specific pointers that can't be dereferenced and only serve as error indicators (e.g. you could have more than just one undereferenceable pointer like NULL and your ERROR_ZERO is a possible candidate)

我通常不鼓励在程序中使用硬编码和魔术指针.

I would generally discourage use of hard-coded and magic pointers in programs.

如果由于某种原因,指针是传达错误情况的唯一方法,并且存在多个错误情况,则可以执行以下操作:

If for some reason, a pointer is the only way to communicate error conditions and there are more than one of them, you could do this:

char ErrorVars[5] = { 0 };
void* ErrorPointer1 = &ErrorVars[0];
void* ErrorPointer2 = &ErrorVars[1];
...
void* ErrorPointer5 = &ErrorVars[4];

然后可以在不同的错误情况下返回ErrorPointer1ErrorPointer1,然后将返回值与它们进行比较.不过,这里有一个警告.您不能使用>>=<<=在法律上将返回的指针与任意指针进行比较.只有当两个指针都指向或指向同一个对象时,这才是合法的.因此,如果您想要这样的快速检查:

You can then return ErrorPointer1 through ErrorPointer1 on different error conditions and then compare the returned value against them. There' a caveat here, though. You cannot legally compare a returned pointer with an arbitrary pointer using >, >=, <, <=. That's only legal when both pointers point to or into the same object. So, if you wanted a quick check like this:

if ((char*)(p = myFunction()) >= (char*)ErrorPointer1 &&
    (char*)p <= (char*)ErrorPointer5)
{
  // handle the error
}
else
{
  // success, do something else
}

仅当p等于这5个错误指针之一时才合法.如果不是,则您的程序可以合法地以任何可以想象和无法想象的方式运行(这是因为C标准如此规定).为了避免这种情况,您必须分别将指针与每个错误指针进行比较:

it would only be legal if p equals one of those 5 error pointers. If it's not, your program can legally behave in any imaginable and unimaginable way (this is because the C standard says so). To avoid this situation you'll have to compare the pointer against each error pointer individually:

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标准规定的那样起作用即可(例如,指针算术可与它们配合使用).这个主题有一个好问题.

Again, what a pointer is and what its representation is, is compiler- and OS/CPU-specific. The C standard itself does not mandate any specific representation or range of valid and invalid pointers, so long as those pointers function as prescribed by the C standard (e.g. pointer arithmetic works with them). There's a good question on the topic.

因此,如果您的目标是编写可移植的C代码,请不要使用硬编码和魔术"指针,而更喜欢使用其他内容来传达错误条件.

So, if your goal is to write portable C code, don't use hard-coded and "magic" pointers and prefer using something else to communicate error conditions.

这篇关于各种平台上的指针地址范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆