.Net / C #: каков реальный размер целого числа?

в .Net целые числа являются типами значений, что означает, что они хранятся в стеке. Целые числа также являются классом (обычно System.Int32). У них есть такие методы, как CompareTo, Equals, ... Таким образом, они должны занимать в стеке более четырех байтов. Однако в приведенном ниже примере показано, что они занимают ровно 4 байта:

unsafe static void Main()
{
    int a = 2, b = 4;
    Console.WriteLine("Adress of a : {0}", (int)&a);
    Console.WriteLine("Adress of b : {0}", (int)&b);
    Console.WriteLine("Size of integer: {0}", (int)(&a) - (int)(&b));
}

Вывод:

Adress of a : 1372876
Adress of b : 1372872
Size of integer: 4

Обеспечивает ли среда CLR особую обработку целочисленных и других типов значений (float, long, double, ...)?


person Community    schedule 01.03.2009    source источник
comment
Я думаю, что int32 - это структура, а не класс.   -  person Shawn    schedule 02.03.2009
comment
Попробуйте запустить это в 64-битной ОС ...   -  person Curt Hagenlocher    schedule 02.03.2009
comment
даже тогда платформа хранит целые числа как 4 байта. native int это другое дело. хотя плохой пример может иметь другое значение, я допускаю   -  person ShuggyCoUk    schedule 02.03.2009
comment
Матьё по-своему рассчитывать размер очень хрупко. используйте вместо этого sizeof (). msdn.microsoft.com/en-us/library/eahchzkf.aspx   -  person ShuggyCoUk    schedule 02.03.2009
comment
Таким образом, они должны занимать в стеке более четырех байтов, почему? Какие метаданные вам нужно хранить, поскольку это переменная стека?   -  person Aron    schedule 29.05.2014


Ответы (4)


Нет, тот факт, что они являются типами значений, не означает, что они хранятся в стеке. Это означает, что они хранятся везде, где находится переменная.

Но послушайте, давайте перейдем к делу с локальными переменными, и в этот момент (без захватов и т. Д.) Они действительно живут в стеке. И они берут 4 байта. Зачем им брать больше? Нет необходимости в vtable в стеке, потому что метаданные уже определяют тип: нет двусмысленности относительно того, какие виртуальные методы будут вызываться и т. Д.

РЕДАКТИРОВАТЬ: как указано в комментарии Шона (но я хотел сделать это более очевидным), System.Int32 - это структура, а не класс. (Фактически, CLR создаст теневой ссылочный тип, чтобы покрыть упакованные значения целых чисел, но это другое дело.)

person Jon Skeet    schedule 01.03.2009
comment
чтобы было ясно, знает ли компилятор тип переменной, для которой вызывается метод, и указанный метод непосредственно определен в этом классе (если виртуальный, тогда должно быть переопределение в классе / структуре) тогда вызов, описанный в IL, содержит всю необходимую информацию, поэтому упаковка не требуется - person ShuggyCoUk; 02.03.2009

Таким образом, они должны занимать в стеке более четырех байтов.

Этого не следует. Компилятор и среда выполнения знает точный тип. Типы значений не могут быть разделены на другие подтипы, поэтому нет необходимости в "vtable" или другом специфическом для объекта механизме динамической диспетчеризации.

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

person Richard    schedule 01.03.2009

Тип значения выделяется в стеке, если это локальная переменная в методе. Если тип значения является членом класса, он будет выделен как часть области памяти объекта в куче.

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

Тип ссылки размещен в куче, и у него есть ссылка (или несколько), которая указывает на него. Сама ссылка на самом деле является типом значения, поэтому это будет просто указатель, компилятор отслеживает, где она находится и какого типа. Тип ссылки не обязательно должен совпадать с типом объекта, на который она указывает, поэтому объекту требуется дополнительная информация для отслеживания типа. Например, ссылка на объект, указывающая на экземпляр класса StringBuilder:

object o = new StringBuilder();

Здесь компилятор отслеживает, что тип ссылки является объектом, поэтому это будет просто указатель (4 байта в 32-битном приложении). Объект StringBuilder хранится в куче, и у него есть два дополнительных указателя, которые отслеживают фактический тип.

Тип значения также может быть упакован в коробку, то есть сохранен как объект в куче. Это происходит, когда вы приводите тип значения к Object:

object p = 42;

Это выделит объект в куче и скопирует в него значение целого числа. Этому объекту потребуется дополнительная информация о типе, чтобы отслеживать тип, поэтому он будет использовать 12 байтов в куче вместо четырех (в 32-битном приложении).

person Guffa    schedule 01.03.2009
comment
В вашем примере StringBuilder два дополнительных указателя являются частью ссылки или объекта? а почему два, а не только один? Спасибо. - person ; 02.03.2009
comment
Нет, восемь байтов не включают ссылку, они являются частью объекта в куче. Указатель на таблицу виртуальных методов и еще четыре байта, которые не очень хорошо документированы ... Вот еще немного информации: stackoverflow.com/questions/489805/ - person Guffa; 02.03.2009
comment
Просто чтобы быть разборчивым: если это локальная переменная в методе, и эта переменная не записана в замыкание, и метод не является блоком итератора ;-p - person Marc Gravell; 02.03.2009

Есть разница между определением типа и значением, хранящимся, например, для экземпляра этого типа ...

// type definition
public class Bla {}
// instance of type bla
public Bla myBla = new Bla();

по сути, размер int такой, как кажется (4 байта), но, как вы уже догадались, это размер пространства памяти, которое требуется для объявления.

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

person War    schedule 20.05.2011