How can one portably perform pointer arithmetic with single byte precision?
Keep in mind that:
char
is not 1 byte开发者_如何学Python 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.
sizeof(char)
always returns 1, in both C and C++. A char
is always one byte long.
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.
精彩评论