Уменьшение загрузки стека, выделение памяти в C и простое приведение возвращаемого значения malloc () - PullRequest
0 голосов
/ 06 января 2010
  1. Известно, что большие локальные / глобальные переменные могут вызвать переполнение стека. Я знаю, что использование указателей и выделение места в памяти помогает решить эту проблему. Но это единственный вариант? Что произойдет, если у меня будет (или нужно) слишком много указателей в глобальной области видимости?

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

  3. Распределяет ли следующий код память также для переменной char ** с именем BIG?

    // in the header file  
    typedef struct myStruct {  
        BIG[256][256];  
        int baz;  
    } myStruct;
    
    // in the c file  
    myStruct* foo;  
    foo = (myStruct*) malloc( sizeof(*foo) ); 
    
  4. Как я могу легко привести возвращаемое значение malloc()? На вопрос № 3 я написал:

    foo = (myStruct*) malloc( sizeof(*foo) );

    Но я предпочитаю написать что-то вроде:

    foo = (foo) malloc( sizeof(*foo) ); // the compiler reports an error

    Что облегчит боль при редактировании кода (при изменении типа foo).

Английский не мой родной язык, поэтому извините за отсутствие ясности.

Ответы [ 5 ]

5 голосов
/ 06 января 2010
  1. Глобалы не создаются в стеке.

  2. См. 1.

  3. Да.

  4. Вы можете опустить приведение:

    foo = malloc (sizeof (* foo));

3 голосов
/ 06 января 2010

Нейл уже ответил на ваши вопросы, вот мои комментарии к вашим 3-м и 4-м вопросам.

Распределяет ли следующий код память также для переменной char** с именем BIG?

typdef struct myStruct {
    char BIG[256][256];
    int baz;
} myStruct;

myStruct* foo;

foo = (myStruct*) malloc( sizeof(*foo) );

(я исправил ошибку в типе BIG.) Это выделит место для BIG, хотя BIG не относится к типу char **. BIG имеет тип «массив [256] массива [256] из char». В контексте значений это эквивалентно «указателю на массив [256] из char».


Как я могу легко привести возвращаемое значение malloc ()? На вопрос № 3 я написал:

foo = (myStruct*) malloc( sizeof(*foo) );

Но я предпочитаю писать что-то вроде:

foo = (foo) malloc( sizeof(*foo) ); // the compiler reports an error

Вы почти правы в том, что хотите сделать, но правильный путь требует еще меньше печатания! Наиболее идиоматичный, удобный для чтения и «безопасный при смене типа» способ:

#include <stdlib.h>
foo = malloc(sizeof *foo);

Или, в более общем смысле,

#include <stdlib.h>
T *foo = malloc(size * sizeof *foo);

Никаких приведений не требуется, так как malloc() возвращает void *, который может быть преобразован в любой тип указателя взад и вперед без потери информации. Обратите внимание, что эта форма не использует тип foo в вызове malloc(), поэтому она не зависит от типа. Кроме того, оператору sizeof не нужны круглые скобки, если он используется для объекта (но они нужны, если он используется для типа).

2 голосов
/ 06 января 2010
  1. Они «в другом месте». Если вы когда-нибудь обнаружите необходимость иметь так много глобальных переменных, с которыми у вас возникнут проблемы, ваш исходный код будет беспорядочным, поэтому вы будете его реорганизовывать. Или вы покупаете большую машину.

  2. Глобалы не создаются в стеке.

  3. Да, это создаст пространство для всей структуры. Однако: ваш БОЛЬШОЙ участник НЕ является чарсом **. Его тип char [256] [256] (при условии, что вы просто пропустили 'char' в своем вопросе)

  4. В C вам не нужно приводить возвращаемое значение malloc. void * присваивается любому указателю. Так что просто сделай

    foo = malloc (sizeof (* foo));

Обратите внимание, что foo является указателем, foo = (foo) malloc (sizeof (* foo)); не имеет смысла, так как в этом случае foo является переменной, а не типом.

1 голос
/ 06 января 2010

1 и 2: переменные области видимости (глобальные) имеют статический экстент, что означает, что они хранятся не так, как локальные (авто) переменные, и не должны вызывать переполнение стека. Честно говоря, если вы переполняете стек из-за того, что ваши (локальные) переменные слишком велики или у вас их слишком много, или если вы регулярно исчерпываете память из кучи, то вам нужно сделать шаг назад и пересмотреть свой дизайн. 1001 *

3 и 4:

Идиоматический способ использования malloc() -

T *p = malloc(sizeof *p * number_of_elements);

В вашем случае вы бы назвали это

myStruct *foo = malloc(sizeof *foo);

или

myStruct *foo;
...
foo = malloc(sizeof *foo);

Если вы не работаете с очень старым (до C89) компилятором, или вы компилируете этот код как C ++ (в этом случае вы должны использовать new вместо malloc(), вам не нужно разыгрывать результат malloc(), и на самом деле практика не рекомендуется.

1 голос
/ 06 января 2010

Если вам действительно нужно привести код возврата malloc (вы используете компилятор C ++?), Вы можете попробовать

foo = (typeof(foo))malloc(sizeof(*foo));

Или даже сделать для него макрос:

#define NEW(A) do {A = (typeof(A))malloc(sizeof(*A));} while (0)
...
NEW(A);

typeof - это расширение GCC .

...