[英]converting uint8_t[4] to uint32_t and back again in C
我编写了这个测试来将uint8[4]
转换为uint32_t
,但是我如何将u32
的输出转换回原始的uint8[4]
? 我认为它可以通过位移以同样的方式完成,但我不确定如何......
uint32_t u32(uint8_t b[4]){
uint32_t u;
u = b[0];
u = (u << 8) + b[1];
u = (u << 8) + b[2];
u = (u << 8) + b[3];
return u;
}
void p(uint32_t value){
printf("\nuint32: %u\n",value);
}
int main(){
uint8_t b[4];
char a[4] = "test";
char tmp[32];
int i;
for(i=0;i<4;i++){
b[i] = a[i];
sprintf(tmp,"%s%u",tmp,b[i]);
}
printf("uint8: ");
for(i=0;i<4;i++)
printf("%u",b[i]);
uint32_t t2 = u32(b);
p(t2);
return 0;
}
我试着做一些不同的事情,使用已知的功能而不是自我实现。 我的主要观点是告诉你字节位于内存中,你给它们的解释取决于上下文。 请注意,有一些字节序问题需要注意。 此外,最好的教训是使用按位运算。
#include <stdint.h>
#include <stdio.h>
#include <arpa/inet.h>
int main()
{
uint8_t a[4]={0x1,0x2,0x3,0x4};
uint32_t b = *((uint32_t*) a);
/* turning an array to unit32 */
printf("0x%x\n",htonl(b));
/* turn an uint32 to array */
uint32_t c = htonl(b);
uint8_t d[4] = {0};
printf("0x%x\n",c);
for (int i=0; i<4 ;++i)
d[i] = ((uint8_t*)&c)[3-i];
for (int i=0; i<4 ;++i)
printf("0x%x\n",d[i]);
return 0;
}
输出是:
0x1020304
0x1020304
0x1
0x2
0x3
0x4
反汇编[您可以使用lldb 或 gdb加载程序]:
root# otool -tv a.out
a.out:
(__TEXT,__text) section
_main:
0000000100000e50 pushq %rbp
0000000100000e51 movq %rsp, %rbp
0000000100000e54 subq $0x30, %rsp
0000000100000e58 movl $0x0, 0xfffffffffffffffc(%rbp)
0000000100000e5f movl 0x12b(%rip), %eax
0000000100000e65 movl %eax, 0xfffffffffffffff8(%rbp)
0000000100000e68 movl 0xfffffffffffffff8(%rbp), %eax
0000000100000e6b movl %eax, 0xfffffffffffffff4(%rbp)
0000000100000e6e movl 0xfffffffffffffff4(%rbp), %edi
0000000100000e71 callq 0x100000f50
0000000100000e76 leaq 0x117(%rip), %rdi
0000000100000e7d movl %eax, %esi
0000000100000e7f movb $0x0, %al
0000000100000e81 callq 0x100000f66
0000000100000e86 movl 0xfffffffffffffff4(%rbp), %edi
0000000100000e89 movl %eax, 0xffffffffffffffe0(%rbp)
0000000100000e8c callq 0x100000f50
0000000100000e91 movl $0x0, %esi
0000000100000e96 movabsq $0x4, %rdx
0000000100000ea0 leaq 0xffffffffffffffec(%rbp), %rcx
0000000100000ea4 movl %eax, 0xfffffffffffffff0(%rbp)
0000000100000ea7 movq %rcx, %rdi
0000000100000eaa callq 0x100000f60
0000000100000eaf leaq 0xde(%rip), %rdi
0000000100000eb6 movl 0xfffffffffffffff0(%rbp), %esi
0000000100000eb9 movb $0x0, %al
0000000100000ebb callq 0x100000f66
0000000100000ec0 movl $0x0, 0xffffffffffffffe8(%rbp)
0000000100000ec7 movl %eax, 0xffffffffffffffdc(%rbp)
0000000100000eca cmpl $0x4, 0xffffffffffffffe8(%rbp)
0000000100000ed1 jge 0x100000efe
0000000100000ed7 movl $0x3, %eax
0000000100000edc subl 0xffffffffffffffe8(%rbp), %eax
0000000100000edf movslq %eax, %rcx
0000000100000ee2 movb 0xfffffffffffffff0(%rbp,%rcx), %dl
0000000100000ee6 movslq 0xffffffffffffffe8(%rbp), %rcx
0000000100000eea movb %dl, 0xffffffffffffffec(%rbp,%rcx)
0000000100000eee movl 0xffffffffffffffe8(%rbp), %eax
0000000100000ef1 addl $0x1, %eax
0000000100000ef6 movl %eax, 0xffffffffffffffe8(%rbp)
0000000100000ef9 jmpq 0x100000eca
0000000100000efe movl $0x0, 0xffffffffffffffe4(%rbp)
0000000100000f05 cmpl $0x4, 0xffffffffffffffe4(%rbp)
0000000100000f0c jge 0x100000f3c
0000000100000f12 leaq 0x7b(%rip), %rdi
0000000100000f19 movslq 0xffffffffffffffe4(%rbp), %rax
0000000100000f1d movzbl 0xffffffffffffffec(%rbp,%rax), %esi
0000000100000f22 movb $0x0, %al
0000000100000f24 callq 0x100000f66
0000000100000f29 movl %eax, 0xffffffffffffffd8(%rbp)
0000000100000f2c movl 0xffffffffffffffe4(%rbp), %eax
0000000100000f2f addl $0x1, %eax
0000000100000f34 movl %eax, 0xffffffffffffffe4(%rbp)
0000000100000f37 jmpq 0x100000f05
0000000100000f3c movl $0x0, %eax
0000000100000f41 addq $0x30, %rsp
0000000100000f45 popq %rbp
0000000100000f46 ret
0000000100000f47 nopw (%rax,%rax)
__OSSwapInt32:
0000000100000f50 pushq %rbp
0000000100000f51 movq %rsp, %rbp
0000000100000f54 movl %edi, 0xfffffffffffffffc(%rbp)
0000000100000f57 movl 0xfffffffffffffffc(%rbp), %edi
0000000100000f5a bswapl %edi
0000000100000f5c movl %edi, %eax
0000000100000f5e popq %rbp
0000000100000f5f ret
您的u32()
函数是读取大端数的主机端不可知代码的一个很好的练习。
它当然可以轻松反转,只需从结尾开始并转到函数的开头,反汇编uint32_t
:
void u8from32 (uint8_t b[4], uint32_t u32)
b[3] = (uint8_t)u32;
b[2] = (uint8_t)(u32>>=8);
b[1] = (uint8_t)(u32>>=8);
b[0] = (uint8_t)(u32>>=8);
}
另一种可能的解决方案具有最少的计算资源需求,没有可怕的铸造并且非常便携。
uint32_t v = 0x11223344;
union ui32_to_ui8 {
uint32_t ui32;
uint8_t ui8[4];
};
ui32_to_ui8 u;
// ----- uint32_t => uint8_t array ------------------------
u.ui32 = v;
// you can read off like this
for (unsigned idx = 0; idx < 3; ++idx) {
b[idx] = u.ui8[idx]; // tx each byte
}
// OR you can do this
b[0] = u.ui8[0];
b[1] = u.ui8[1];
b[2] = u.ui8[2];
b[3] = u.ui8[3];
// ----- uint8_t array => uint32_t ------------------------
for (unsigned idx = 0; idx < 3; ++idx) {
u.ui8[idx] = b[idx];
}
v = u.ui32; // read out the 32 bit value.
使用位掩码。
例如:
0xabcd & 0xff00 = 0xab00
0xabcd & 0x00ff = 0x00cd
对于 32 位术语,同样的想法也适用。 只需掩盖您想要的区域,然后根据需要向右移动。
为了从uint8_t
和uint32_t
转换回来,我发现这些函数很有用:
uint32_t u8_to_u32(const uint8_t* bytes) {
// Every uint32_t consists of 4 bytes, therefore we can shift each uint8_t
// to an appropriate location.
// u32 ff ff ff ff
// u8[] 0 1 2 3
uint32_t u32 = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
return u32;
}
// We pass an output array in the arguments because we can not return arrays
uint8_t* u32_to_u8(const uint32_t u32, uint8_t* u8) {
// To extract each byte, we can mask them using bitwise AND (&)
// then shift them right to the first byte.
u8[0] = (u32 & 0xff000000) >> 24;
u8[1] = (u32 & 0x00ff0000) >> 16;
u8[2] = (u32 & 0x0000ff00) >> 8;
u8[3] = u32 & 0x000000ff;
}
这是一个测试这些功能的程序:
#include <stdio.h>
#include <stdint.h>
uint32_t u8_to_u32(const uint8_t* bytes) {
uint32_t u32 = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
return u32;
}
void u32_to_u8(const uint32_t u32, uint8_t* u8) {
u8[0] = (u32 & 0xff000000) >> 24;
u8[1] = (u32 & 0x00ff0000) >> 16;
u8[2] = (u32 & 0x0000ff00) >> 8;
u8[3] = u32 & 0x000000ff;
}
int main() {
uint8_t test_1_u8[4] = {0x12, 0x34, 0x56, 0x78};
uint32_t test_1_u32 = u8_to_u32(test_1_u8);
printf("test_1_u32 == 0x12345678 -> %d\n", test_1_u32 == 0x12345678);
uint32_t test_2_u32 = 0x87654321;
uint8_t test_2_u8[4];
u32_to_u8(test_2_u32, test_2_u8);
printf("0x87654321 can be rewritten as\n0x87, 0x65, 0x43, 0x21\n");
printf("0x87 == test_2_u8[0] -> %d\n", 0x87 == test_2_u8[0]);
printf("0x65 == test_2_u8[1] -> %d\n", 0x65 == test_2_u8[1]);
printf("0x43 == test_2_u8[2] -> %d\n", 0x43 == test_2_u8[2]);
printf("0x21 == test_2_u8[3] -> %d\n", 0x21 == test_2_u8[3]);
return 0;
}
我得到的输出是:
test_1_u32 == 0x12345678 -> 1
0x87654321 can be rewritten as
0x87, 0x65, 0x43, 0x21
0x87 == test_2_u8[0] -> 1
0x65 == test_2_u8[1] -> 1
0x43 == test_2_u8[2] -> 1
0x21 == test_2_u8[3] -> 1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.