How can one portably perform pointer arithmetic with single byte precision?
Keep in mind that:
char
is not 1 byte on all platformssizeof(void) == 1
is only available as an extension in GCC- While some platforms may have pointer deref pointer alignment restrictions, arithmetic may still require a finer granularity than the size of the smallest fundamental POD type
Your assumption is flawed - sizeof(char)
is defined to be 1 everywhere.
From the C99 standard (TC3), in section 6.5.3.4 ("The sizeof operator"):
(paragraph 2)
The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type.
(paragraph 3)
When applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1.
When these are taken together, it becomes clear that in C, whatever size a char is, that size is a "byte" (even if that's more than 8 bits, on some given platform).
A char
is therefore the smallest addressable type. If you need to address in units smaller than a char
, your only choice is to read a char
at a time and use bitwise operators to mask out the parts of the char
that you want.
According to the standard char
is the smallest addressable chunk of data. You just can't address with greater precision - you would need to do packing/unpacking manually.
sizeof(char)
is guaranteed to be 1
by the C standard. Even if char
uses 9 bits or more.
So you can do:
type *pt;
unsigned char *pc = (unsigned char *)pt;
And use pc
for arithmetic. Assigning pc
to pt
by using the cast above is undefined behavior by the C standard though.
If char
is more than 8-bits wide, you can't do byte-precision pointer arithmetic in portable (ANSI/ISO) C. Here, by byte, I mean 8 bits. This is because the fundamental type itself is bigger than 8 bits.
Cast the pointer to a uintptr_t
. This will be an unsigned integer that is the size of a pointer. Now do your arithmetic on it, then cast the result back to a pointer of the type you want to dereference.
(Note that intptr_t
is signed, which is usually NOT what you want! It's safer to stick to uintptr_t
unless you have a good reason not to!)
I don't understand what you are trying to say with sizeof(void)
being 1 in GCC. While type char
might theoretically consist of more than 1 underlying machine byte, in C language sizeof(char)
is 1 and always exactly 1. In other words, from the point of view of C language, char
is always 1 "byte" (C-byte, not machine byte). Once you understand that, you'd also understand that sizeof(void)
being 1 in GCC does not help you in any way. In GCC the pointer arithmetic on void *
pointers works in exactly the same way as pointer arithmetic on char *
pointers, which means that if on some platform char *
doesn't work for you, then void *
won't work for you either.
If on some platform char
objects consist of multiple machine bytes, the only way to access smaller units of memory than a full char
object would be to use bitwise operations to "extract" and "modify" the required portions of a complete char
object. C language offers no way to directly address anything smaller than char
. Once again char
is always a C-byte.
The C99 standard defines the uint8_t that is one byte long. If the compiler doesn't support this type, you could define it using a typedef. Of course you would need a different definition, depending on the the platform and/or compiler. Bundle everything in a header file and use it everywhere.
来源:https://stackoverflow.com/questions/1864956/byte-precision-pointer-arithmetic-in-c-when-sizeofchar-1