Как глобальные переменные влияют на размер исполняемого файла? - PullRequest
3 голосов
/ 04 декабря 2010

Увеличивает ли наличие глобальных переменных размер исполняемого файла?Если да, то как?Увеличивает ли он только размер раздела данных или также размер текстового раздела?

Если у меня есть глобальная переменная и инициализация, как показано ниже:

char g_glbarr[1024] = {"jhgdasdghaKJSDGksgJKASDGHKDGAJKsdghkajdgaDGKAjdghaJKSDGHAjksdghJKDG"};

Теперь это добавляет 1024 к разделу данныхи размер строки инициализации в текстовый раздел?

Если вместо этого, если статически выделять место для этого массива, если я его выделю, а затем сделаю memcpy, то уменьшится только размер раздела данных или размер текстового разделаи уменьшит?

Ответы [ 4 ]

5 голосов
/ 04 декабря 2010

Да, это так. В основном компиляторы хранят их в сегменте данных. Иногда, если вы используете постоянный массив символов в вашем коде (например, printf("<1024 char array goes here");), он переходит в сегмент данных (AFAIK, некоторые старые компиляторы / Borland? / Могут хранить его в текстовом сегменте). Вы можете заставить компилятор поместить глобальную переменную в пользовательский раздел (для VC ++ это было #pragma data_seg(<segment name>)).

Динамическое выделение памяти не влияет на сегменты данных / текста, поскольку оно выделяет память в куче.

3 голосов
/ 04 декабря 2010

Ответ зависит от реализации, но для здравомыслящих реализаций это то, как он работает для переменных со статической длительностью хранения (глобальной или иной):

  • Всякий раз, когда переменная инициализируется, все инициализированное значение объекта будет сохранено в исполняемом файле. Это верно, даже если только его начальная часть явно инициализирована (остальная часть неявно равна нулю).
  • Если переменная постоянна и инициализирована, она будет находиться в сегменте «текст» или эквивалентна. Некоторые системы (современные на основе ELF, может быть, также и Windows?) Имеют отдельный сегмент «родата» для данных только для чтения, чтобы их можно было пометить как неисполняемые, отдельно от программного кода.
  • Непостоянные инициализированные переменные будут находиться в сегменте «данные» в исполняемом файле, который отображается операционной системой при копировании в память в режиме копирования при записи.
  • У неинициализированных переменных (которые в соответствии со стандартом неявно равны нулю) не будет зарезервировано хранилище в самом исполняемом файле, но есть размер и смещение в сегменте "bss", который создается во время загрузки программы операционной системой.
  • Такие неинициализированные переменные могут быть созданы в отдельном доступном только для чтения сегменте, похожем на bss, если они const -квалифицированы.
2 голосов
/ 04 декабря 2010

Я не выступаю в качестве эксперта, но я предполагаю, что просто наличие этого эпического строкового литерала в вашей программе увеличит размер вашего исполняемого файла. То, что вы делаете с этим строковым литералом, не имеет значения, потому что оно должно храниться где-то .

Почему имеет значение, какой "раздел" исполняемого файла увеличен? Это не риторический вопрос!

1 голос
/ 04 декабря 2010

Ответ слегка зависит от реализации, но в целом нет. Ваш g_glbarr действительно является указателем на char или адресом. Сама строка будет помещена в раздел данных с постоянными строками, и g_glbarr станет символом адреса строки во время компиляции. Вы не заканчиваете тем, что выделяете место для указателя, и компилятор просто разрешает адрес во время ссылки.

Обновление

@ Джей, вроде как то же самое. Целые числа (как правило) просто встроены: компилятор подойдет как можно ближе к простой константе в коде, потому что это настолько распространенный случай, что большинство нормальных архитектур имеют простой способ сделать это из непосредственных данных. Строковые константы все еще будут находиться в некотором разделе данных только для чтения. Поэтому, когда вы делаете что-то вроде:

// warning: I haven't compiled this and wouldn't normally
// do it quite this way so I'm not positive this is
// completely grammatical C
struct X {int a; char * b; } x = { 1, "Hello" } ; 

1 становится "непосредственными" данными, "Hello" выделяется где-то в данных только для чтения, и компилятор просто генерирует что-то, что выделяет часть данных для чтения-записи, которая выглядит примерно как

x:
x.a:   WORD    1
x.b    WORD    @STR42

где STR42 - символическое имя для расположения строки "Hello" в памяти. Затем, когда все связано, @STR42 заменяется фактическим виртуальным адресом строки в памяти.

...