Арифметика указателя с точностью до байта в C, когда sizeof(char) != 1

StackOverflow https://stackoverflow.com/questions/1864956

Вопрос

Как можно портативно выполнять арифметику указателей с точностью до одного байта?

Имейте в виду, что:

  • char не равен 1 байту на всех платформах
  • sizeof(void) == 1 доступен только как расширение в GCC
  • Хотя на некоторых платформах могут быть ограничения на выравнивание указателя по разыменованию указателя, арифметика все равно может требовать более тонкой детализации, чем размер наименьшего фундаментального типа POD.
Это было полезно?

Решение

Ваше предположение ошибочно - sizeof(char) является определенный быть 1 везде.

Из Стандарт C99 (TC3), в разделе 6.5.3.4 («Оператор sizeof»):

(пункт 2)

Оператор Size Of дает размер (в байтах) своего операнда, который может быть выражением или в скобках названия типа.

(пункт 3)

При применении к операнду, который имеет тип char, unsigned char или подписанный char, (или квалифицированная версия), результат составляет 1.

Когда они взяты вместе, становится ясно, что в C, каким бы ни был размер символа, этот размер является «байтом» (даже если он превышает 8 бит на какой-то конкретной платформе).

А char следовательно, это наименьший адресуемый тип.Если вам нужно адресовать в единицах меньше, чем char, ваш единственный выбор - прочитать char одновременно и используйте побитовые операторы для маскировки частей char что ты хочешь.

Другие советы

sizeof(char) всегда возвращает 1, в обоих C и С++char всегда имеет длину один байт.

По стандарту char — это наименьший адресуемый фрагмент данных.С большей точностью вы просто не сможете адресоваться — придется делать упаковку/распаковку вручную.

sizeof(char) гарантированно будет 1 по стандарту C.Даже если char использует 9 бит или более.

Итак, вы можете сделать:

type *pt;
unsigned char *pc = (unsigned char *)pt;

И используйте pc для арифметики. Назначение pc к pt Однако использование приведенного выше приведения является неопределенным поведением по стандарту C.

Если char имеет ширину более 8 бит, вы не можете выполнять арифметику указателей с точностью до байта в портативном (ANSI/ISO) C.Здесь, по байт, Я имею в виду 8 бит.Это связано с тем, что сам фундаментальный тип больше 8 бит.

Наведите указатель на uintptr_t.Это будет целое число без знака размером с указатель.Теперь выполните арифметические действия, а затем приведите результат обратно к указателю того типа, который вы хотите разыменовать.

(Обратите внимание, что intptr_t подписано, а это обычно НЕ то, что вам нужно!Безопаснее придерживаться uintptr_t если у вас нет веских причин не делать этого!)

Я не понимаю, что ты пытаешься сказать sizeof(void) быть 1 в GCC.Пока печатаете char теоретически может состоять из более чем 1 базового машинного байта на языке C sizeof(char) равно 1 и всегда ровно 1.Другими словами, с точки зрения языка C, char всегда равен 1 «байту» (C-байт, а не машинный байт).Как только вы это поймете, вы поймете и это. sizeof(void) Быть 1 в GCC вам никак не поможет.В GCC арифметика указателей на void * указатели работают точно так же, как арифметика указателей на char * указатели, а это значит, что если на какой-то платформе char * тогда тебе не подходит void * у тебя тоже не пойдет.

Если на какой-то платформе char объекты состоят из нескольких машинных байтов, и это единственный способ получить доступ к меньшим единицам памяти, чем полная char Целью было бы использование побитовых операций для «извлечения» и «изменения» необходимых частей полного char объект.Язык C не предлагает возможности напрямую обращаться к чему-либо меньшему, чем char.Снова char всегда является C-байтом.

Стандарт C99 определяет uint8_t длиной в один байт.Если компилятор не поддерживает этот тип, вы можете определить его с помощью typedef.Конечно, вам понадобится другое определение, в зависимости от платформы и/или компилятора.Объедините все в заголовочный файл и используйте везде.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top