2012-08-09 29 views
2

我有一个四字节的DWORD,我需要分成四个不同的字符。我以为我知道如何做到这一点,但每次都得到奇怪的数字。这里是我的代码:C++打破DWORD为字符

// The color memory 
    int32 col = color_mem[i]; 

    // The four destination characters 
    char r, g, b, a; 

    // Copy them in advancing by one byte every time 
    memcpy(&r, &col, 1); 
    memcpy(&g, &col + 1, 1); 
    memcpy(&b, &col + 2, 1); 
    memcpy(&a, &col + 3, 1); 
+1

什么是color_mem的类型? – ryanbwork 2012-08-09 22:52:11

回答

8

memcpy和使用位操作:

r = (col & 0x000000ff); 
g = (col & 0x0000ff00) >> 8; 
b = (col & 0x00ff0000) >> 16; 
a = (col & 0xff000000) >> 24; 

ff在十六进制数字代表所有1位的字节。这和& - 位与 - 会让你是不感兴趣的字节 - 在每个位置 - 0,并保持你感兴趣的位

>>轮换着从零左侧,外放。我们想要的最重要位置的字节,用于实际分配。 8位移位一个字节的宽度,16位是两个字节,24位是三个字节。

从视觉上看,在ff,你可以想象,我们走向左边的字节索引。

+0

你能推荐一个关于这个主题的好教程吗?似乎我应该知道的东西。 – 2012-08-09 22:51:24

+0

任何好的C书都会介绍这个,看看K&R的_The C Programming Language_。另外一个[这里](http://www.cprogramming.com/tutorial/bitwise_operators.html) – pb2q 2012-08-09 22:52:53

+0

正如发布这将工作,如果字节排序是big-endian;在小端平台(x86,x64等)上,为了与OP的意图相匹配,您需要进行相反的处理:a =(col&0xff000000)>> 24; b =(col&0x00ff0000)>> 16; g =(col&0x0000ff00)>> 8; r =(col&0x000000ff);' – 2012-08-09 22:59:58

4

当您进行指针运算时,增量或减量的数量乘以指向的类型的大小。将int32指针指向char指针,以便访问char大小的部件,其偏移距基地址为col

由于不同平台上字节序的差异,这种技术可能很脆弱,所以我建议使用另一个答案中提供的更便携的位掩码操作。

// The color memory 
int32 col = color_mem[i]; 

// The four destination characters 
char r, g, b, a; 

// Copy them in advancing by one byte every time 
memcpy(&r, (char*)&col, 1); 
memcpy(&g, ((char*)&col) + 1, 1); 
memcpy(&b, ((char*)&col) + 2, 1); 
memcpy(&a, ((char*)&col) + 3, 1); 
1

因为山坳是一个Int32 +1增加了4个字节

搜索对谷歌

指针算术
2

添加+1到INT32将使地址去了4个字节的偏移量。

您可以使用memcpy(&g, reinterpret_cast<char *>(&col)+1, 1)等。

更好的办法:

int32 col = color_mem[i]; 

struct splitted4byte 
{ 
    char r; 
    char g; 
    char b; 
    char a; 
} 

splitted4byte rgb; 

memcpy(&rgb, &col, 4); 

你应该关心的字节在col的方式顺序。我不知道int32的哪个部分是哪种颜色。

你应该阅读关于排序。 (谷歌它,有文件)

当R最高值和其他颜色为0,如果它存储为1111 1111 0000 0000 0000 0000 0000 0000,我的意思是如果整数表示的颜色RGBA(255,0,0,0)等于这个二进制值。它将在内存中反向排序,即0000 0000 0000 0000 0000 0000 1111 1111,因此您需要计算此值。

您可以使用网络转换函数将网络字节顺序(big-endian)转换为主机字节顺序(小端或大端)。这样你就不需要根据机器来改变你的代码。 (函数是ntohl(网络到主机长),也有htons(主机到网络短)等2字节,也有64toh()为64位整数,但该函数只能退出Unix变种if我记得没错。) 所有你需要做的是int32 col = ntohl(color_mem[i]);

或者你可以使你的结构顺序根据这个,但这样你的代码将无法在big-endian上工作。

0

每个人都给出了不同的答案,并且无论如何都是正确的。有些是特定于endian的(如按位操作)。其他人不是。为了清楚起见,我可能做到这一点:

char *bytes = (char*)&color_mem[i]; 
char r = bytes[0]; 
char g = bytes[1]; 
char b = bytes[2]; 
char a = bytes[3]; 

我看不出有任何理由使用memcpy。即使有结构。结构分配是一种语言功能 - 您不必复制它。

还没有看到工会的任何提及,可是...

union Pixel { 
    DWORD packed; 
    struct Components { 
     char r, g, b, a; 
    }; 
    char bytes[4]; 
}; 

// You can just specify your image data like this... 
Pixel *pixels = (Pixel*)color_mem; 

// Reference one pixel for convenience - don't need to reference, you can 
// just copy it instead if you want (alternative: Pixel p = pixels[i]) 
Pixel &p = pixels[i]; 

char r = p.r; 
char g = p.g; 
char b = p.b; 
char a = p.a; 

int32 col = p.packed; 

这是尾数中性的:它不依赖于一个整数的组织。通常这很好,但你仍然需要意识到它。