Распределение памяти обратного адреса в C и Objective-C - PullRequest
1 голос
/ 11 февраля 2012

В функции C память ее локальных пользователей выделяется при вызове функции и освобождается при завершении функции. Как насчет функций, которые возвращают значение (например, int, string), , когда и где выделяет и освобождает ли память обратного адреса, является ли она частью стека вызовов или стек вызовов или что-то еще?

Рассмотрим следующий пример:

int* foo()
{
   int _myInt;
   return(&_myInt);
}

Этот пример приводит меня в замешательство относительно того, как выделяется память для адреса возврата , который возвращает указатель. Может кто-нибудь объяснить, пожалуйста?

То же самое для C и Objective-C?

Ответы [ 4 ]

4 голосов
/ 11 февраля 2012

Я не знаю об Objective-C, но при стандартном C возвращаемые значения обычно хранятся в регистрах.

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

Рассмотрим следующую функцию:

char* GetStr()
{
    char buff[50];
    strcpy(buff, "Hello, World!");
    return buff;
}

Эта функция возвращает указатель на локальную память, которая освобождается при возврате функции.Доступ к этой памяти представляет собой ошибку с неопределенным поведением.

Это также относится к вашему примеру, что недопустимо.Но так как int может поместиться в регистр, вы можете просто сделать return _myInt; и вернуть значение напрямую.

3 голосов
/ 11 февраля 2012

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

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

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

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

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

3 голосов
/ 11 февраля 2012

В Obj-C, если вы выделили объект с помощью вызова alloc, стандартная практика заключается в том, чтобы автоматически высвобождать этот объект перед возвратом и называть метод так, чтобы вызывающая сторона знала, что он получает объект, который автоматически высвобождается. Если вызывающий абонент нуждается в этом, он может снова сохранить этот объект.

- (MyClass *)getMyAutoreleasedObject {
    MyClass *obj = [[MyClass alloc] init];
    return [obj autorelease];  // caller needs to retain if needed
}

А если у вас нет автоматического выпуска, вы должны назвать метод таким образом, чтобы вызывающая сторона знала, что он должен освободить возвращенный объект. Это строго соблюдаемое соглашение в Obj-C.

В C, если вы выделяете память в стеке, эта память недопустима в вызывающей программе.

int *func() {
    int a[100];
    return a;  // invalid in caller
}

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

int *func() {
    int *a = (int *) malloc (100 * sizeof(int));
    return a;  // caller must free(a)
}
0 голосов
/ 11 февраля 2012

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

...