Как работает sizeof для типов int?

У меня есть небольшая программа, которая сравнивает

(1) sizeof, (2) numeric_limits::digits, (3) и результаты цикла

чтобы убедиться, что все они сообщают одно и то же о размере «типов int» в любой реализации C++. Однако, поскольку я не знаю о внутренностях sizeof, я должен задаться вопросом, просто ли он сообщает numeric_limits::digits. Спасибо


person Community    schedule 16.05.2011    source источник
comment
Много дубликатов: попробуйте выполнить поиск, а затем, если вы не найдете результат, спрашивайте, но об этом уже спрашивали раньше, и тривиальный поиск как sizeof work дает несколько результатов. Я голосую за закрытие.   -  person David Rodríguez - dribeas    schedule 17.05.2011
comment
возможный дубликат Как работает sizeof? Как я могу написать свой собственный?   -  person David Rodríguez - dribeas    schedule 17.05.2011


Ответы (3)


Скорее всего, sizeof() в большинстве компиляторов заставляет компилятор искать данный тип (или тип объекта) в своей внутренней таблице типов и вставлять литерал для определенного размера этого типа в генерируемый им код. Это произойдет во время компиляции, а не во время выполнения.

Чтобы ответить на вопрос в комментариях, в C++ нет никакого языково-определяемого доступа к внутренним компонентам компилятора (кроме таких вещей, как сам sizeof(), конечно). Единственный известный мне похожий язык, который позволяет делать подобные вещи, — это Ada, который предоставляет ASIS. для написания независимых от компилятора инструментов анализа кода.

person T.E.D.    schedule 16.05.2011
comment
Вы случайно не знаете, как я могу вручную найти значение во внутренней таблице типов? Спасибо. - person ; 17.05.2011
comment
@Chris: для типа T sizeof(T) дает этот конкретный бит данных. Менее педантичный ответ - нет, если только ваш конкретный компилятор не позволяет вам, и тогда результат, вероятно, будет зависеть от того, какие флаги вы установили. - person Dennis Zickefoose; 17.05.2011
comment
Таким образом, чтобы обобщить, это значение в таблице (слышали символическую таблицу и таблицу типов), оцениваемое во время компиляции. - person ; 17.05.2011

Оператор sizeof — это конструкция времени компиляции, с помощью которой компилятор сообщает размер в байтах, который экземпляр данного типа будет занимать в памяти.

Трудно дать общий ответ «вот как работает sizeof», потому что он специфичен для каждой реализации компилятора. В общем, он работает, вычисляя размер каждого поля типа и складывая их вместе с учетом выравнивания.

Например, вот разумный набор выходов [1]

struct S1 {
  int field1;
  int field2;
};

struct S2 {
  int field1;
  bool field2;
  int field3;
}

sizeof(S1) == 8
sizeof(S2) == 12;

Причина, по которой многие компиляторы сообщают размер S2 как 12, а не 9, заключается в том, что он должен учитывать проблемы с выравниванием и, следовательно, вставлять 3 байта, чтобы восполнить пробел между field2 и field3.

[1] Примечание: я сказал разумно, но не гарантировано :). Компиляции C имеют большую гибкость в размерах, и почти невозможно указать конкретные размеры, не зная компилятора, с которым вы работаете.

person JaredPar    schedule 16.05.2011

В sizeof не так много внутренних элементов; это встроенный оператор, который сообщает размер своего операнда (либо выражение, либо тип) в байтах.

Ваш код довольно сложен, и использование typeid оставляет меня в недоумении...

У меня есть двуязычная программа (написанная на подмножестве C C++), которая выдает такие ответы:

 1 = sizeof(char)
 1 = sizeof(unsigned char)
 2 = sizeof(short)
 2 = sizeof(unsigned short)
 4 = sizeof(int)
 4 = sizeof(unsigned int)
 8 = sizeof(long)
 8 = sizeof(unsigned long)
 4 = sizeof(float)
 8 = sizeof(double)
16 = sizeof(long double)
 8 = sizeof(size_t)
 8 = sizeof(ptrdiff_t)
 8 = sizeof(time_t)
 8 = sizeof(void *)
 8 = sizeof(char *)
 8 = sizeof(short *)
 8 = sizeof(int *)
 8 = sizeof(long *)
 8 = sizeof(float *)
 8 = sizeof(double *)
 8 = sizeof(int (*)(void))
 8 = sizeof(double (*)(void))
 8 = sizeof(char *(*)(void))
 1 = sizeof(struct { char a; })
 2 = sizeof(struct { short a; })
 4 = sizeof(struct { int a; })
 8 = sizeof(struct { long a; })
 4 = sizeof(struct { float a; })
 8 = sizeof(struct { double a; })
16 = sizeof(struct { char a; double b; })
16 = sizeof(struct { short a; double b; })
16 = sizeof(struct { long a; double b; })
 4 = sizeof(struct { char a; char b; short c; })
16 = sizeof(struct { char a; char b; long c; })
 4 = sizeof(struct { short a; short b; })
 6 = sizeof(struct { char a[3]; char b[3]; })
 8 = sizeof(struct { char a[3]; char b[3]; short c; })
16 = sizeof(struct { long double a; })
32 = sizeof(struct { char a; long double b; })

(Это было создано G++ 4.6.0 на MacOS X 10.6.7 — 64-битная компиляция). Код, который я использовал:

#ifdef __cplusplus
#define __STDC_CONSTANT_MACROS
#endif /* __cplusplus */

#include <stdio.h>
#include <time.h>
#include <stddef.h>
#if __STDC_VERSION__ >= 199901L || HAVE_INTTYPES_H
#include <inttypes.h>
#endif /* __STDC_VERSION__ */

/* Using the simple C code in SPRINT() for structures leads to complaints from G++ */
/* Using the code in TPRINT() for pointers to functions leads to other complaints */
#define TPRINT(x)   do { typedef x y; printf("%2u = sizeof(" #x ")\n", (unsigned int)sizeof(y)); } while (0)
#define SPRINT(x)   printf("%2u = sizeof(" #x ")\n", (unsigned int)sizeof(x))

int main(void)
{
    /* Basic Types */
    SPRINT(char);
    SPRINT(unsigned char);
    SPRINT(short);
    SPRINT(unsigned short);
    SPRINT(int);
    SPRINT(unsigned int);
    SPRINT(long);
    SPRINT(unsigned long);

    SPRINT(float);
    SPRINT(double);
    SPRINT(long double);
    SPRINT(size_t);
    SPRINT(ptrdiff_t);
    SPRINT(time_t);

    /* Fancy integers */
#if __STDC_VERSION__ >= 199901L || HAVE_LONG_LONG
    SPRINT(long long);
    SPRINT(unsigned long long);
#endif /* __STDC_VERSION__ || HAVE_LONG_LONG */
#if __STDC_VERSION__ >= 199901L || HAVE_INTTYPES_H
    SPRINT(uintmax_t);
#ifdef INT8_MAX
    SPRINT(int8_t);
#endif
#ifdef INT16_MAX
    SPRINT(int16_t);
#endif
#ifdef INT32_MAX
    SPRINT(int32_t);
#endif
#ifdef INT64_MAX
    SPRINT(int64_t);
#endif
#ifdef INT128_MAX
    SPRINT(int128_t);
#endif
    SPRINT(int_least8_t);
    SPRINT(int_least16_t);
    SPRINT(int_least32_t);
    SPRINT(int_least64_t);
    SPRINT(int_fast8_t);
    SPRINT(int_fast16_t);
    SPRINT(int_fast32_t);
    SPRINT(int_fast64_t);
    SPRINT(uintptr_t);
#endif /* __STDC_VERSION__ || HAVE_INTTYPES_H */

    /* Pointers */
    SPRINT(void *);
    SPRINT(char *);
    SPRINT(short *);
    SPRINT(int *);
    SPRINT(long *);
    SPRINT(float *);
    SPRINT(double *);

    /* Pointers to functions */
    SPRINT(int (*)(void));
    SPRINT(double (*)(void));
    SPRINT(char *(*)(void));

    /* Structures */
    TPRINT(struct { char a; });
    TPRINT(struct { short a; });
    TPRINT(struct { int a; });
    TPRINT(struct { long a; });
    TPRINT(struct { float a; });
    TPRINT(struct { double a; });
    TPRINT(struct { char a; double b; });
    TPRINT(struct { short a; double b; });
    TPRINT(struct { long a; double b; });
    TPRINT(struct { char a; char b; short c; });
    TPRINT(struct { char a; char b; long c; });
    TPRINT(struct { short a; short b; });
    TPRINT(struct { char a[3]; char b[3]; });
    TPRINT(struct { char a[3]; char b[3]; short c; });
    TPRINT(struct { long double a; });
    TPRINT(struct { char a; long double b; });
#if __STDC_VERSION__ >= 199901L || HAVE_LONG_LONG
    TPRINT(struct { char a; long long b; });
#endif /* __STDC_VERSION__ */
#if __STDC_VERSION__ >= 199901L || HAVE_INTTYPES_H
    TPRINT(struct { char a; uintmax_t b; });
#endif /* __STDC_VERSION__ || HAVE_INTTYPES_H */

    return(0);
}

Я точно не помню, почему мне пришлось возиться с __STDC_CONSTANT_MACROS и SPRINT() против TPRINT(), но это, похоже, было необходимо (еще в марте 2010 года), чтобы сделать код двуязычным.

person Jonathan Leffler    schedule 16.05.2011
comment
Однако вы должны отметить, что это вывод 64-битного компьютера. Длинный int в 32-битной системе равен 4 байтам вместо 8-битных, а длинные двойные числа составляют всего 12 байтов в 32-битной системе, а указатели имеют размер 4 байта вместо 8 байтов. - person DipSwitch; 17.05.2011
comment
@DipSwitch: да, это 64-битный компилятор. Ответы по своей сути зависят от платформы. В Windows 64, например, sizeof(long) == 4 по-прежнему, хотя на большинстве 64-битных Unix-машин sizeof(long) == 8. В этом разница между системами ILP32, LP64, ILP64, LLP64. - person Jonathan Leffler; 17.05.2011