#c #sizeof
Вопрос:
Правда ли, что:
- Нет указателя на данные больше, чем
sizeof(void *)
? - Нет указателя на данные больше, чем
sizeof(char *)
? - Никакое целое число не больше, чем
sizeof(intmax_t)
? - Ни
float
то, ниdouble
другое не больше, чемsizeof(long double)
?
Я знаю, что intmax_t
может хранить любое значение, которое может хранить любое другое целое число со знаком, но требуется ли, чтобы размер также был наибольшим размером любого целого числа? Или возможно, что какое-то другое целое число использует так много битов заполнения intmax_t
, что размер этого целого числа становится больше, чем intmax_t
даже тогда, когда это целое число не может содержать какое-либо значение, которое intmax_t
не может содержать?
Аналогично указателям, я знаю, что любой другой указатель данных может быть преобразован в char *
void *
и обратно без потери информации, но означает ли это, что размер char *
и void *
должен быть максимально возможным размером всех указателей данных?
Я задаю этот вопрос, потому что у меня есть функция в библиотеке, которая преобразует строку в другой тип, который обозначается целым числом. Чтобы проверить, можно ли выполнить этот диалог для данной строки (формат правильный), существует функция, которая проверяет это для разных типов данных, функция должна зарезервировать достаточно памяти для всех возможных типов, выполнить диалог, проверить наличие ошибок и снова освободить эту память. Достаточно ли этого, чтобы убедиться, что он достаточно велик intmax_t
, чтобы охватить все целочисленные типы?
Комментарии:
1. Стандарт C не требует этого. Реализация может, скажем, включать метаданные , с
int *
которыми она не имеетvoid *
, делаяint *
их большеvoid *
, даже если она не может охватить столько различных местоположений. Или он мог бы просто сказать «трахнись иfloat
набери сотню неиспользуемых байтов». Или, может быть, avoid *
составляет всего восемь байт для доступа к любому 64-разрядному адресу, но все указатели функций составляют 16 байт, потому что они содержат некоторую информацию о безопасности.2. @EricPostpischil К указателям на функции: В C нет требований, которые
void *
могли бы содержать указатель на функцию, на самом деле на некоторых микроконтроллерах с гарвардской архитектурой указатель на функцию больше, чемvoid *
. В остальном: это относится к ответу.3. Короткая нетехническая версия представляет собой указатель-это указатель-это указатель (и для любой данной реализации существует только один размер).
stdint.h
Типintmax_t
может содержать любое целое значение со знаком, и без учета нечетных 12-битных чисел с плавающей запятой или точности, превышающейdouble
и т. Д. Тогда, как правило, можно с уверенностью предположить, что ниfloat
то, ни другое илиdouble
большеlong double
. Но, как уже отмечалось, стандарт конкретно не отвечает на ваш вопрос, поэтому он будет зависеть от конкретной реализации (хотя я не знаю ни одного, который нарушал бы ваши утверждения).4. Существует причина, по которой стандарт C не требует, чтобы «указатель-это указатель-это указатель (и для любой данной реализации существует только один размер)». Причина в том, что это просто неверно для нескольких (ранее) важных архитектур. c-faq.com/null/machexamp.html
5. «Ни одно целое число не больше, чем sizeof(intmax_t)» —
sizeof(intmax_t)
обычно равно 4 или 8.
Ответ №1:
Есть intptr_t
сейчас, которое гарантированно работает; однако платформы прошлых лет, на которых intptr_t
нужно было бы быть больше, чем ptrdiff_t
нет intptr_t
, потому что они заморожены во времени, а собственные компиляторы для целевых платформ просто не имеют этого. Если у вас есть современный компилятор, такой как OpenWatcom, ориентированный на старые архитектуры, он будет работать.
Хотя они исправили это для кросс-компиляции современных компиляторов во встроенные процессоры, вы в конечном итоге получаете другие аберрации, которые могут существовать вместо этого, которые так же плохи и одинаково трудны для проверки. У компиляторов, с которыми мне приходилось иметь дело во встроенном мире, были некоторые реальные неприятности; если они типичны, попытка создать нейтральную для платформы библиотеку, которая не предполагает плоской архитектуры, чревата перлом:
- Значение NULL не равно 0. Это означает, что
memset()
это не инициализирует указатели в структурах на NULL и не делаетcalloc()
этого ; и они не являются нулевыми, когда объявлены как статические, если явно не инициализированы наNULL
. sizeof(char *) < sizeof(const char *)
иsizeof(void *) < sizeof(const void *)
; этот конкретный компилятор не давалintptr_t
иptrdiff_t
не мог содержать результат произвольного вычитания двух указателей в одном и том же массиве символов (но этого можно было избежать, сделав массив символов не больше PTRDIFF_T_MAX).- Компилятор не реализовал C99 и не имел
intptr_t
иptrdiff_t
был слишком мал, чтобы содержать указатель. free()
ничего не сделал- Компилятор статически удалил тесты с нулевым указателем, где он мог доказать, что указатель указывает на структуру, но NULL был возможным адресом глобальной переменной.
Я никогда не пытался заставить нетривиальную библиотеку работать во встроенном мире и, конечно, никогда не сталкивался с такими указателями, как этот.
TL;DR Все ваши четыре утверждения должны быть верными, но когда их подвергают испытанию огнем, где это имеет значение, вы в конечном итоге сталкиваетесь с уродством.
Мне приходит в голову, что вы конвертируете между указателем и строкой sprintf
и sscanf
у вас есть спецификаторы формата, которые могут это сделать.
Комментарии:
1. Первое и последнее предложение неверно.
2. где
intptr_t
должно быть больше, чемptrdiff_t
нетintptr_t
, я не понимаю, почему это должно быть так, или вот что: если вы не можете привести указатель вptrdiff_t
безопасноеintmax_t
положение, его вообще не будет , можете ли вы объяснить, почему это должно быть так? AFAIK: Эти утверждения неверны для некоторых компиляторов 8051.3. OpenWatcom для 8086, использующий модель большой памяти, является примером компилятора/библиотеки , которая использует 32-разрядный код для
intptr_t
, ноptrdiff_t
имеет только 16-разрядный код иintmax_t
существует. Является ли это несоответствием? github.com/jmalak/open-watcom/blob/master/bld/hdr/watcom/…4. @12431234123412341234123: Большое обновление для ответа; Я добавил много материала из встроенного мира. Я удивлен, что кто-то поддерживает компилятор x86-16 в соответствии с современными стандартами, но это так, поэтому я включил его в ответ.