Сколько занимает памяти void c
приведенный выше код выводит адрес функции demo .
Поэтому, если мы можем напечатать адрес функции, что означает, что эта функция присутствует в памяти и занимать место в ней.
Так сколько же места она занимает в памяти?
поэтому, если мы можем напечатать адрес функции, это означает, что это функция присутствует в памяти и занимает в ней некоторое пространство.
да, функции вы пишете компилируются в код, который хранится в памяти. (в случае интерпретируемого языка сам код хранится в памяти и выполняется интерпретатором.)
Итак, сколько места он занимает в память?
объем памяти полностью зависит от функции. вы можете написать очень длинный и очень короткий. Длинный потребует больше памяти. Пространство, используемое для кода, обычно не является тем, о чем вам нужно беспокоиться, если вы не работаете в среде с серьезными ограничениями памяти, например, в очень маленькой встроенной системе. На настольном компьютере (или даже мобильном устройстве) с современной операционной системой система виртуальной памяти будет позаботьтесь о перемещении страниц кода в физическую память или из нее по мере необходимости, поэтому очень мало шансов, что ваш код будет потреблять слишком много памяти.
вы можете увидеть сами, используя objdump -r -d :
редактировать
Я взял ваш код и скомпилировал (но не связал!) он. Используя objdump вы можете видеть фактический способ компилятора выкладывает код для запуска. В конце концов, нет такой вещи, как функция: для CPU это просто прыжок в какое-то место (которое в этом списке помечено). Таким образом, размер "функции" - это размер кода, который ее содержит.
там кажется, какая-то путаница в том, что это как-то не "реальный код". Вот что говорит GDB:
это точно такой же код, с точно таким же размером, исправленный компоновщиком для использования реальных адресов. gdb печать смещений в десятичном формате в то время как objdump использует более благоприятный hex. Как видите, в обоих случаях размер составляет 21 байт.
Да, все функции, которые вы используете в своем коде, занимают пространство памяти. Однако пространство памяти не обязательно принадлежит исключительно вашей функции. Например, inline функция будет занимать пространство внутри каждой функции, откуда она вызывается.
стандарт не предоставляет способа определить, сколько места занимает функция в памяти, поскольку арифметика указателя, трюк, который позволяет вычислять размеры смежных областей памяти в памяти данных, не определяется для указатель функции. Кроме того, ISO C запрещает преобразование указателя функции в тип указателя объекта, поэтому вы не можете обойти это ограничение, приведя указатель функции, скажем, char* .
вышеуказанный код печатает адрес функции demo() .
это неопределенное поведение: %p ждет void* , в то время как вы проходите его void (*)() . Вы должны увидеть предупреждение компилятора, сообщающее, что то, что вы делаете, недопустимо (демо).
Что касается определения объема памяти, которую он занимает, это невозможно во время выполнения. Однако есть и другие способы определить это: Как получить длину функции в байтах?
функции компилируются в машинный код,который будет работать только на определенном ISA (x86, вероятно, ARM, если он будет работать на вашем телефоне и т. д.) Поскольку разным процессорам может потребоваться больше или меньше инструкций для запуска одной и той же функции, а длина инструкций также может варьироваться, нет способа заранее точно узнать, насколько велика функция, пока вы ее не скомпилируете.
даже если вы знаете, для какого процессора и операционной системы он будет скомпилирован, разные компиляторы будет создавать различные эквивалентные представления функции в зависимости от того, какие инструкции они используют и как они оптимизируют код.
кроме того, имейте в виду, что функция занимает память по-разному. Я думаю, вы говорите о самом коде, который является его собственным разделом. Во время выполнения, эта функция также может занимать место в стеке - каждый раз, когда функция вызывается, больше памяти в виде стека. Сумма зависит от количества и типа локальные переменные и аргументы, объявленные функции.
да, однако вы можете объявить его встроенным, поэтому компилятор возьмет исходный код и переместит его туда, где вы вызываете эту функцию. Также можно использовать макросы препроцессора. Хотя имейте в виду, что использование inline будет генерировать больший код, но он будет выполняться быстрее, и компилятор может решить игнорировать ваш встроенный запрос, если он чувствует, что он станет большим.
Когда я создаю метод типа int, компилятор резервирует X количество бит в памяти. Итак, как вид типа void? Сколько бит/байтов занимает тип void?
спросил(а) 2009-05-05T23:20:00+04:00 12 лет, 6 месяцев назадЭто просто тип указателя undefined, поэтому размер - это размер любого другого указателя на систему, в которой вы его создаете.
ответил(а) 2009-05-05T23:25:00+04:00 12 лет, 6 месяцев назадтип void не принимает никаких битов. вы не можете объявить переменную типа void. это:
вызывает ошибку компиляции.
void - это просто место, которое означает "ничего", функция, которая возвращает void, возвращает ничего, а функция, которая принимает значение void как аргумент, не принимает аргументов.
Однако вы можете объявить переменную типа void *:
Это просто объявляет указатель, который может указывать на что-либо, что когда-либо было. как любой указатель, он принимает размер типа указателя, т.е. sizeof (void *), который обычно равен 4 в 32-битных системах.
ответил(а) 2009-05-05T23:26:00+04:00 12 лет, 6 месяцев назадВ архитектуре x86 (с использованием gcc 3.4.6) возвращаемое значение функций int сохраняется в регистре eax. Номера с плавающей запятой возвращаются через регистр XMM или в ST0. [Редактировать: Thanks Bastien Leonard!]
Функции Void просто не помещают ничего в eax и возвращают.
строит с помощью gcc -S:
с определенным f2:
и f1 определены:
Если другие люди получают разные коды из разных версий gcc, было бы интересно увидеть XD (возможно, в других ситуациях функции int возвращаются в стек. )
Я бы предположил, что во всех реализациях функция void просто ничего не возвращает. Он либо оставляет только регистры возврата и/или ничего не падает на стек (или в).
ответил(а) 2009-05-05T23:42:00+04:00 12 лет, 6 месяцев назадЯ думаю, что предположение о том, как компилятор сохраняет возвращаемые значения, может быть слишком общим. Что происходит с возвращаемыми значениями, определяется языком, типом и оборудованием.
Может существовать "регистр возврата", который мог бы удерживать значение возврата, поэтому память не была бы занята. "Возвратный регистр" также может указывать на некоторые выделенные в памяти на основе возвращаемого типа.
Я не понимаю, почему функция, возвращающая void, когда-либо выделяла память для возвращаемого значения.
ответил(а) 2009-05-05T23:23:00+04:00 12 лет, 6 месяцев назадФункция возвращает void , вызывающий не ожидает никакого возвращаемого значения, и ничего не нужно выделять. void не является реальным типом, который должен быть возвращен, это больше указывает на компилятор, что функция ничего не возвращает.
На ПК функции возвращают простые значения, такие как int , помещая их в определенный регистр ( eax ); компилятор просто генерирует соответствующий код для извлечения этого значения. (И если функция возвращает void , тогда компилятор не генерирует этот тип кода.)
На других архитектурах вызывающий может неявно передать параметр, указывающий на int , где будет помещено возвращаемое значение.
Этот тип низкоуровневых материалов не определяется стандартами C и С++. Он может быть указан другим стандартом, или это может быть просто соглашение.
Когда я создаю метод типа int, компилятор резервирует в памяти X битов. Так как же увидеть тип void? Сколько бит / байтов занимает тип void?
Тип void не принимает никаких битов. вы не можете объявить переменную типа void. это:
Вызывает ошибку компиляции.
void - это просто заполнитель, который означает «ничего», функция, которая возвращает void, ничего не возвращает, а функция, которая принимает void в качестве аргумента, не принимает аргументов.
Однако вы можете объявить переменную типа void *:
Это просто объявляет указатель, который может указывать на что угодно и когда угодно. как и любой указатель, он принимает размер типа указателя, то есть sizeof (void *), который обычно равен 4 в 32-битных системах.
Я думаю, что ваше предположение о том, как компилятор хранит возвращаемые значения, может быть слишком общим. Что происходит с возвращаемыми значениями, определяется языком, типом и оборудованием.
Может быть «регистр возврата», который может содержать значение возврата, поэтому память не будет занята. «Регистр возврата» может также просто указывать на некоторую выделенную память в зависимости от возвращаемого типа.
Я не понимаю, почему функция, возвращающая void, когда-либо выделяла память для возвращаемого значения.
В архитектуре x86 (с использованием gcc 3.4.6) возвращаемое значение функций int хранится в регистре eax. Числа с плавающей запятой возвращаются через регистр XMM или в ST0. [Edit: Спасибо, Бастьен Леонард!]
Функции Void просто ничего не помещают в eax и не возвращают.
Строит с gcc -S для:
С определением f2:
И f1 определены:
Если другие люди получат другой код из разных версий gcc, было бы интересно увидеть XD (возможно, в других ситуациях функции int возвращаются в стек . )
Однако я могу представить, что во всех реализациях функция void просто ничего не возвращает. Он либо оставляет регистры возврата в покое, либо ничего не сбрасывает в стек (или в него).
Если функция возвращает void , вызывающий не ожидает никакого возвращаемого значения, и ничего не нужно выделять. void не является реальным типом, который нужно возвращать, это скорее указание компилятору, что функция ничего не возвращает.
На ПК функции возвращают простые значения, такие как int , помещая их в определенный регистр ( eax ); компилятор просто генерирует соответствующий код для получения этого значения. (И если функция возвращает void , компилятор не генерирует такой код.)
На других архитектурах вызывающий может неявно передать параметр, указывающий на int , куда будет помещено возвращаемое значение.
Такие низкоуровневые вещи не определены стандартами C и C ++. Это может быть определено другим стандартом, или это может быть просто соглашение.
Это просто неопределенный тип указателя, поэтому размер равен размеру любого другого указателя в системе, в которой вы его создаете.
Вы можете использовать pandas.DataFrame.fillna с опцией method='ffill' . 'ffill' означает «прямое заполнение» и будет распространять последнее действительное наблюдение вперед. Альтернативой является 'bfill' , который работает одинаково, но обратный.
Для этого также существует функция прямого синонима, pandas.DataFrame.ffill , чтобы сделать вещи проще .
Тип void не имеет размера; это будет ошибка компиляции. По той же причине вы не можете сделать что-то вроде:
EDIT. К моему удивлению, выполнение sizeof(void) на самом деле делает компиляцию в GNU C:
Однако в C ++ это не:
Но GCC имеет возможность рассматривать «sizeof (void) == sizeof (char)» . См. -Wpointer-arith – Jonathan Leffler 3 November 2009 в 10:37 @ Jon это для дураков с начала 80-х годов, которые только начали учиться программированию. Стандарты не получили широкого распространения. – unixman83 16 July 2011 в 15:56 sizeof (void) является нарушением ограничения. Соответствующий компилятор C (который gcc не по умолчанию) должен, по крайней мере, предупреждать об этом, и может (и IMHO) отклонить его. Ссылка: N1570 6.5.3.4p1 ( void является неполным типом). Так было со стандартом 1989 года, который ввел void . – Keith Thompson 1 February 2015 в 04:06 @ unixman83: Это не имеет смысла. void не существовало до того, как оно было введено стандартом ANSI C 1989 года, тем же стандартом, который сделал sizeof (void) нарушение ограничения. – Keith Thompson 1 February 2015 в 04:06sizeof() не может применяться к неполным типам. И void является неполным типом, который не может быть завершен.
В C, sizeof(void) == 1 в GCC, но это зависит от вашего компилятора.
Только в GCC sizeof (void) == 1; в стандарте это неопределенное поведение. – Jonathan Leffler 3 November 2009 в 10:38 Обновлено для добавления специального примечания GCC. – Greg Hewgill 3 November 2009 в 10:48 @JonathanLeffler: Это не просто неопределенное поведение. Это нарушение ограничений. N1570 6.5.3.4p1. – Keith Thompson 1 February 2015 в 04:08Если вы используете GCC, и вы не используете флагов компиляции, которые удаляют специфические расширения для компилятора, тогда sizeof(void) равно 1. GCC имеет нестандартное расширение , которое делает это.
В общем случае void является неполным типом, и вы не можете использовать sizeof для неполных типов.
Опция -Wpointer-arith подразумевается -pedantic . Я всегда использовал -pedantic . :) – Josh Lee 3 November 2009 в 13:13 @jleedev В самом деле, я также использую -патентный, насколько могу. К сожалению, однако, некоторые сторонние заголовки библиотеки делают gcc -pedantic очень грустным :( – hrnt 11 November 2009 в 16:33 +1 Действительно, почему у GCC есть тысячи бесполезных расширений? – user 25 January 2012 в 23:42 @ user142019: потому что они полезны? И помогает получать согласованную бэкэнд-модель с помощью разных языков программирования и аппаратной архитектуры. – kriss 26 November 2014 в 16:00void не имеет размера. В C и C ++ выражение sizeof (void) недействительно.
В C, цитируя N1570 6.5.3.4, пункт 1:
Оператор sizeof не должен применяться к выражению, имеющему тип функции или неполному типу , к имени в скобках такого типа или выражению, которое обозначает член битового поля.
(N1570 - проект стандарта ISO C 2011 года.)
Стандарт C ++ 11 имеет очень похожую формулировку. Оба выпуска были опубликованы после того, как этот вопрос был задан, но правила восходят к стандарту ANSI C 1989 года и самым ранним стандартам C ++. На самом деле правило, что void является неполным типом, к которому sizeof не может применяться, возвращается точно так же, как введение void в язык.
gcc имеет extension , который рассматривает sizeof (void) как 1. gcc по умолчанию не является совместимым компилятором C, поэтому в режиме по умолчанию он не предупреждает о sizeof (void) . Расширения, подобные этому, разрешены даже для полностью совместимых компиляторов C, но диагностика по-прежнему требуется.
@GrzegorzSzpetkowski: (Ответ через пару лет.) Да, стандарт требует диагностики, но gcc по умолчанию не является совместимым компилятором C. Логически, стандарт C не предъявляет никаких требований к реализациям, которые не претендуют на то, чтобы соответствовать ему. gcc можно сделать (почти) соответствующим параметрам командной строки, например -std=c11 -pedantic . С такими параметрами он выдает необходимую диагностику. – Keith Thompson 7 September 2017 в 23:59Хотя void может стоять на месте для типа, он фактически не может удерживать значение. Поэтому он не имеет размера в памяти. Получение размера void не определено.
Указатель void - это просто языковая конструкция, означающая указатель на память untyped .
И что ? Должна ли какая-либо пустая структура не потреблять никакого размера в памяти, и это должно быть проблемой. Ну, на самом деле, мне интересно, если пустые структуры действительно используют 0 байтов в C ++ (как это верно в C) выглядит как sizeof returns 1 для них. – kriss 21 March 2013 в 11:22 @kriss Я не уверен, что вы говорите, но, как вы заметили себя, пустые структуры do занимают память по причинам идентичности объекта. – Konrad Rudolph 21 March 2013 в 11:35 действительно, но это было неверно в C и использование памяти для пустых объектов чувствует зло. – kriss 21 March 2013 в 14:39Большинство компиляторов C ++ выбрали для повышения компиляции при попытке получить sizeof(void) .
При компиляции C gcc не соответствует и решил определить sizeof(void) как 1. Это может показаться странным, но имеет логическое обоснование. Когда вы выполняете арифметику указателя, добавляя или удаляя одну единицу, это означает добавление или удаление объекта, указывающего на размер. Таким образом, определение sizeof(void) как 1 помогает определить void* как указатель на байт (нетипизированный адрес памяти). В противном случае у вас было бы удивительное поведение, используя арифметику указателя, такую как p+1 == p when p void* . Такая арифметика указателя на указателях void не допускается в c ++, но отлично работает при компиляции C с gcc.
. Рекомендуемым стандартным способом было бы использовать char* для этой цели (указатель на байт).
Еще одно подобное различие между C и C ++ при использовании sizeof возникает, когда вы определили пустую структуру типа:
Использование gcc в качестве моего компилятора C sizeof(empty) возвращает 0. Используя g ++ тот же код вернет 1.
Я не уверен, что называет состояние как стандартов C, так и C ++ в этой точке, но я считаю, что определение размера некоторых пустых структур / объектов помогает в управлении ссылками, чтобы избежать этих двух ссылки на разные последовательные объекты, первый из которых пуст, получает тот же адрес. Если ссылка реализована с использованием скрытых указателей, как это часто делается, обеспечение того, что другой адрес поможет их сравнить.
Но это просто избегает неожиданного поведения (сравнение ссылок на столбик) путем введения другого (пустые объекты, даже POD потребляют не менее 1 байт памяти).
Читайте также: