2010-08-07 2 views
1

Итак, у меня есть функция, возвращающая указатель, или NULL при ошибке. Теперь я хотел бы добавить другое возможное значение для другой ошибки/условия. Я слышал, как это упоминалось ранее в другом ответе, используя malloc(), чтобы создать уникальный указатель, который будет служить возможностью для возврата таких функций (теперь теперь можно вернуть правильный указатель, NULL или 0xWhatever, и вы можете быть уверены, что 0xWhatever выиграл ' t использоваться для чего-либо еще). Таким образом, естественно, malloc(1), вероятно, безопасная ставка, но мне было интересно, безопасно ли для этого malloc(0). Возможно ли использовать код malloc(0) для чего-то еще? Может ли кто-нибудь уточнить, как эта техника должна работать вообще, и, может быть, что она называется?Использование malloc() для уникальных указателей

+2

Хотя это другой вопрос, многие решения этой проблемы можно найти в ответ на [Может ли указатель (адрес) когда-либо быть отрицательным?] (http://stackoverflow.com/questions/3304795/can-a-pointer-address-ever-be-negative). –

+0

Ах, вот что я искал, дозорный. –

ответ

5

От стандарта C99:

Если размер пространства запрошенный равен нулю, то поведение определяется реализацией: либо возвращается нулевой указатель, или поведение, как если бы размер были некоторые ненулевые значения, за исключением того, что возвращаемый указатель не должен использоваться для доступа к объекту.

Вам лучше использовать malloc(1). Это гарантирует возврат не-NULL, если память доступна.

2

Насколько я понимаю, в общем, malloc(0) «выделит» память, которую все еще нужно освободить. Это даст вам место в памяти, которое вы не должны писать.

Для получения уникального адреса необязательно использовать malloc(), это может происходить, например, из статического местоположения. Тогда вы можете использовать этот адрес как свое другое условие. Также не учитывается распределение. Я не помню термин для этого использования, что-то про прокси.

#define ERRORPTR ((void *)&_unusedvar) 
static char _unusedvar; 

if (/* failed */) 
    return ERRORPTR; 
+0

Это приятное расширение на ответ @R ... +1. –

+0

@ Карл: больше он повторил мой. ;) Но неважно, ОП получил ответ, который он ищет. –

1

До и я считаю, включая C89, значение было неуказанным. Стандарту просто нечего было сказать о ненулевом (или худшем, отрицательном) размере. Я уверен, что теперь это Реализация определена. Используйте ненулевой размер для переносимости.

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

Другой традиционный подход (используемый в самых ранних версиях signal(), IIRC) заключался в том, чтобы вводить небольшие числа, отличные от 0, к типу указателя. Это на самом деле относительно не переносимо, поскольку единственное целое число, которое переносимо и безопасно отбрасывается на указатель, равно 0, что равно NULL.

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

+0

'malloc' принимает тип unsigned argument (' size_t'), поэтому нет такой вещи, как отрицательный размер. –

+0

@R., Так как стандартизация у него есть, но у меня есть смутные воспоминания хотя бы одного раннего libc, где аргумент размера был 'int' или' long'. Конечно, не очень хорошая идея. K & R вообще не определяет 'malloc()', но показывает реализацию чего-то с именем 'alloc()' как комбинацию примера и упражнения. Он имеет «int n» в качестве аргумента, без каких-либо предостережений относительно нулевых или отрицательных значений. – RBerteig

2

Несколько тангенциальный вопрос, но имеющий «указатель условий ошибки» (кроме NULL), на самом деле не является идиоматическим C. Если вы хотите написать функцию, которая выделяет память указателю и может возвращать несколько отдельных условий ошибки есть еще два обычных способа сделать это:

  1. Набор errno описать вашу конкретную ошибку и вернуть NULL для всех ошибок.
  2. Возьмите указатель на указатель в качестве аргумента и возвращает код ошибки целого

Э.Г.

sometype* my_function() 
{ 
    sometype* p; 

    /* Do something */ 

    if (error_1_occurred) { 
    errno = EAGAIN; /* Or whatever is appropriate */ 
    return NULL; 
    } else if (error_2_occurred) { 
    errno = EINVAL; /* Or whatever is appropriate */ 
    return NULL; 
    } 

    p = malloc(/* whatever */); 

    /* Do stuff */ 

    return p; 
} 

или

int my_function(sometype** pp) { 

    if (!pp) return -99; 

    /* Do something */ 

    if (error_1_occurred) { 
    return -1; 
    } else if (error_2_occurred) { 
    return -2; 
    } 

    *pp = malloc(/* whatever */); 

    /* Do stuff */ 

    return 0; 
} 
+0

Второй пример, как правило, наиболее универсальный. Возьмем, например, asprintf(), который может возвращать множество ошибок или количество фактически напечатанных байтов. –

3

Использование malloc для этой цели является очень плохой практикой. Просто сделать:

static const char myerror; 
return (void *)&myerror; 

, чтобы получить «значение ошибки» указатель, который никогда не будет сравнивать равно указатель на какой-либо реальный объект остальной части программы может получить.

Редактировать: Первоначально я упустил &. Исправлена.

+0

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

1

Указатель - это не что иное, как указатель на адрес ячейки памяти 0, так как память обычно выгружается в 4 тыс. Кусков, вы можете использовать числа от 1 до 4095, чтобы возвращать другие ошибки в вашей функции, потому что этот кусок (0 - 4096) не будет выгружаться для вашего приложения (если вы явно не набросаете его, используя mmap).

Так было бы безопасно сделать что-то вроде:

if(someError) 

    return NULL; 

else if(someOtherError) 

    return (void *)1; 

else 
    /* Do something else */ 
+0

A * константа нулевой указатель * необязательно представлена ​​значением '0'. –

Смежные вопросы