Подтвердить что ты не робот

Занимают ли функции пространство памяти?

void demo()
{
    printf("demo");
}

int main()
{
    printf("%p",(void*)demo);
    return 0;
}

Приведенный выше код печатает адрес функции demo.
Поэтому, если мы можем напечатать адрес функции, это означает, что эта функция присутствует в памяти и занимает некоторое место в ней.
Итак, сколько места оно занимает в памяти?

4b9b3361

Ответ 1

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

Да, функции, которые вы пишете, скомпилированы в код, который хранится в памяти. (В случае интерпретируемого языка сам код хранится в памяти и выполняется интерпретатором.)

Итак, сколько места занимает память в памяти?

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

Ответ 2

Вы можете сами убедиться, используя objdump -r -d:

0000000000000000 <demo>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   bf 00 00 00 00          mov    $0x0,%edi
                        5: R_X86_64_32  .rodata
   9:   b8 00 00 00 00          mov    $0x0,%eax
   e:   e8 00 00 00 00          callq  13 <demo+0x13>
                        f: R_X86_64_PC32        printf-0x4
  13:   5d                      pop    %rbp
  14:   c3                      retq   

0000000000000015 <main>:

ИЗМЕНИТЬ

Я взял ваш код и скомпилировал (но не связал!) его. Используя objdump, вы можете увидеть фактический способ, которым компилятор устанавливает код для запуска. В конце дня нет такой функции, как функция: для CPU это просто переход в какое-то место (что в этом листинге помечено). Таким образом, размер "функции" - это размер кода, который содержит его.


Кажется, есть некоторая путаница, что это как-то не "настоящий код". Вот что говорит GDB:

Dump of assembler code for function demo:
   0x000000000040052d <+0>:     push   %rbp
   0x000000000040052e <+1>:     mov    %rsp,%rbp
   0x0000000000400531 <+4>:     mov    $0x400614,%edi
   0x0000000000400536 <+9>:     mov    $0x0,%eax
   0x000000000040053b <+14>:    callq  0x400410 <[email protected]>
   0x0000000000400540 <+19>:    pop    %rbp
   0x0000000000400541 <+20>:    retq   

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

Ответ 3

Конечно, занимая пространство в памяти, вся программа загружается в память после ее выполнения. Как правило, инструкции программы хранятся в младших байтах пространства памяти, известных как text section. Вы можете узнать больше об этом здесь: http://www.geeksforgeeks.org/memory-layout-of-c-program/

Ответ 4

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

Стандарт не дает способа определить, сколько пространства занимает функция в памяти, как арифметика указателя, трюк, который позволяет вам вычислять размеры смежных областей памяти в памяти данных, не определен для указателей функций. Кроме того, ISO C запрещает преобразование указателя функции на тип указателя объекта, поэтому вы не можете обойти это ограничение, отбросив указатель на, скажем, char*.

printf("%p",demo);

Вышеприведенный код печатает адрес функции demo().

Это поведение undefined: %p ожидает a void*, а вы передаете ему void (*)(). Вы должны увидеть предупреждение компилятора, сообщая, что то, что вы делаете, неверно (demo).

Ответ 6

Функции скомпилированы в машинный код, который будет запускаться только на определенной ISA (x86, возможно, ARM, если он будет работать на вашем телефоне и т.д.). Поскольку для разных процессоров может потребоваться больше или меньше инструкций для запуска той же функции, и длина инструкций также может меняться, нет способа узнать заранее, насколько велика функция, пока вы ее не скомпилируете.

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

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

Ответ 7

Да, однако вы можете объявить его как встроенным, поэтому компилятор возьмет исходный код и переместит его, когда вы вызываете эту функцию. Или вы также можете использовать макросы препроцессора. Хотя имейте в виду, что inline будет генерировать более крупный код, но он будет выполняться быстрее, и компилятор может решить игнорировать ваш встроенный запрос, если он почувствует, что он станет большим.