简体   繁体   中英

What's the correct way to add 1 byte to a pointer in C/C++?

I'm using this code to move pointer by 1 byte now, but I'm feeling something unclear..

int* a = (int*)malloc(sizeof(int));
void* b = ((char*)a)+1;   

char is 1 byte, but not defined for byte operation purpose. I believe there's another way to do this byte operation. What's the correct way to byte operation?

PS. I modified sample code to be valid. It's now compiled as C++ with Clang.

In C99, you have the stdint.h header, which contains int8_t and uint8_t types, which are guaranteed to be 8 bits (and generally are just typedefs for char). Beyond this, there is no real language level support for bytes in C or C++, in fact the standard goes out of its way to say that sizeof for example is in units of char (and not bytes). There is also the CHAR_BIT macro which tells you the number of bits in a byte, on some platforms char was 9bits for example. Of course I'm assuming by byte you mean octet.

I think you are confused:

char is 1 byte, but not defined for byte operation purpose. I believe there's another way to do this byte operation. What's the correct way to byte operation?

What exactly are you expecting byte to mean, if not the exact same thing that char means?

In C and in C++, chars are bytes. By definition . What is not the case is that bytes are necessarily octets . A byte contains at least 8 bits. There is no guarantee that a given platform even makes it possible to reference a chunk of memory that is exactly 8 bits.

((char*)a)++

This is one of those evil Microsoft extensions. A pointer casting expression is an rvalue, but according to the C++ language rules, the increment operator only works on lvalues. g++ refuses to compile this.

You should not do this. Many architectures have data alignment requirements. For example, dereferencing a pointer not aligned to a word boundary on a SPARC machine, will crash the program with a Bus Error ( SIGBUS ).


The portable way to split your int into bytes is by using bitwise operations (assuming 8-bit bytes):

uint8_t b3 = 0x12, b2 = 0x34, b1 = 0x56, b0 = 0x78;
uint32_t a;

a = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;

printf("%08X\r\n", a);

a = 0x89ABCDEF;

b3 = (a >> 24) & 0xFF;
b2 = (a >> 16) & 0xFF;
b1 = (a >> 8) & 0xFF;
b0 = a & 0xFF;

printf("%02X%02X%02X%02X\r\n", b3, b2, b1, b0);

The same can be non-portably achieved with type punning tricks through union s, such as:

typedef union {
    uint32_t val;
    uint8_t  bytes[4];
} DWORD_A;

typedef union {
     uint32_t val;
     struct {
         unsigned b0:8;
         unsigned b1:8;
         unsigned b2:8;
         unsigned b3:8;
     };
} DWORD_B;

However, this technique leads to implementation defined behaviour and thus is not recommended :

  • Byte order depends on host system's endianness.
  • Packing of the bit fields is not portable.
  • Added complexity/overhead due to code generated by the compiler to prevent misaligned access.
  • Alignment issues, on implementations that don't prevent them.
((char*&)a)++;

Or:

a = (int*)((char*)a+1);

I hope you know exactly what you're doing. For one thing, you're ending up with - by definition - unaligned int pointer. Depending on architecture and OS, this might be trouble.

plz, use void*

int g = 10;
int *a = &g;
printf("a : %p\n",a);
printf("a : %p\n", ++a);
printf("a : %p\n", (void*)((char*)a+1));

a : 0xbfae35dc a : 0xbfae35e0 a : 0xbfae35e1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM