Может ли указатель (адрес) быть отрицательным? - PullRequest
33 голосов
/ 22 июля 2010

У меня есть функция, которую я хотел бы иметь возможность возвращать специальные значения для ошибка и неинициализирован (возвращает указатель на успех).

В настоящее времяон возвращает NULL для сбоя и -1 для неинициализированного, и это, кажется, работает ... но я мог бы обмануть систему.IIRC, адреса всегда положительные, не так ли?(хотя компилятор позволяет мне установить адрес -1, это кажется странным).

[update]

Еще одна идея, которая у меня возникла (если -1 был рискованным)malloc символ @ глобальная область и использовать этот адрес в качестве дозорного.

Ответы [ 13 ]

0 голосов
/ 22 июля 2010

На самом деле (по крайней мере в x86) исключение NULL-указателя генерируется не только разыменованием NULL-указателя, но и большим диапазоном адресов (например, первые 65 КБ). Это помогает отлавливать такие ошибки как

int* x = NULL;
x[10] = 1;

Таким образом, существует больше адресов, которые гарантируют генерацию исключения NULL-указателя при разыменовании. Теперь рассмотрим этот код (сделан для компиляции для AndreyT):

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

#define ERR_NOT_ENOUGH_MEM (int)NULL
#define ERR_NEGATIVE       (int)NULL + 1
#define ERR_NOT_DIGIT      (int)NULL + 2

char* fn(int i){
    if (i < 0)
        return (char*)ERR_NEGATIVE;
    if (i >= 10)
        return (char*)ERR_NOT_DIGIT;
    char* rez = (char*)malloc(strlen("Hello World ")+sizeof(char)*2);
    if (rez)
        sprintf(rez, "Hello World %d", i);
    return rez;
};

int main(){
    char* rez = fn(3);
    switch((int)rez){
        case ERR_NOT_ENOUGH_MEM:    printf("Not enough memory!\n"); break;
        case ERR_NEGATIVE:          printf("The parameter was negative\n"); break;
        case ERR_NOT_DIGIT:         printf("The parameter is not a digit\n"); break;
        default:                    printf("we received %s\n", rez);
    };
    return 0;
};

это может быть полезно в некоторых случаях. Он не будет работать на некоторых гарвардских архитектурах, но будет работать на фон Неймана.

0 голосов
/ 22 июля 2010

Джеймс ответ, вероятно, правильный, но, конечно, описывает реализацию выбор, а не выбор, который вы можете сделать.

Лично я думаю, что адреса "интуитивно" не подписаны. Поиск указателя, который сравнивается с нулевым указателем, может показаться неправильным. Но ~0 и -1 для одного целого типа дают одинаковое значение. Если он интуитивно неподписан, ~0 может сделать более интуитивно понятным значение в особом случае - я использую его для беззнаковых целых случаев с ошибками довольно часто. Это не на самом деле отличается (ноль по умолчанию int, поэтому ~0 это -1, пока вы не разыгрываете его), но он выглядит другим.

Указатели в 32-битных системах могут использовать все 32-битные BTW, хотя -1 или ~0 крайне маловероятно, чтобы указатель имел место для подлинного распределения на практике. Существуют также правила, специфичные для платформы - например, в 32-битной Windows процесс может иметь только 2 ГБ адресного пространства, и вокруг много кода, который кодирует какой-либо флаг в верхний бит указателя (например, для балансировки флаги в сбалансированных бинарных деревьях).

0 голосов
/ 22 июля 2010

@ Джеймс, конечно, прав, но я хотел бы добавить, что указатели не всегда представляют абсолютные адреса памяти, что теоретически всегда будет положительным.Указатели также представляют относительные адреса в некоторой точке памяти, часто указатель стека или кадра, и они могут быть как положительными, так и отрицательными.

Поэтому лучше всего, чтобы ваша функция принимала указатель на указатель в качестве параметра и заполняла этот указатель действительным значением указателя в случае успеха, возвращая код результата из фактической функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...