我无法完全理解我在此处阅读的内容的后果:Casting an int pointer to a char ptr and vice versa
简而言之,这会有用吗?
set4Bytes(unsigned char* buffer) {
const uint32_t MASK = 0xffffffff;
if ((uintmax_t)buffer % 4) {//misaligned
for (int i = 0; i < 4; i++) {
buffer[i] = 0xff;
}
} else {//4-byte alignment
*((uint32_t*) buffer) = MASK;
}
}
修改
有一个长时间的讨论(在评论中,神秘地删除了)关于指针应该被铸造到什么类型以检查对齐。现在讨论的主题是here。
答案 0 :(得分:11)
如果您在所有 4个字节中填充相同的值,则此转换是安全的。如果byte order
很重要,那么这种转换就不安全了。
因为当您使用整数一次填充 4字节时,它将填充4 Bytes
,但顺序取决于endianness。
答案 1 :(得分:1)
此代码可能对您有所帮助。它显示通过一次为其内容分配一个字节来构建32位数字,从而强制不对齐。它在我的机器上编译和工作。
#include<stdint.h>
#include<stdio.h>
#include<inttypes.h>
#include<stdlib.h>
int main () {
uint32_t *data = (uint32_t*)malloc(sizeof(uint32_t)*2);
char *buf = (char*)data;
uintptr_t addr = (uintptr_t)buf;
int i,j;
i = !(addr%4) ? 1 : 0;
uint32_t x = (1<<6)-1;
for( j=0;j<4;j++ ) buf[i+j] = ((char*)&x)[j];
printf("%" PRIu32 "\n",*((uint32_t*) (addr+i)) );
}
如@Learner所述,必须遵守字节顺序。上面的代码不可移植,并且会在大端机器上中断。
请注意,我的编译器会抛出错误&#34;从'char *'转换为'unsigned int'会丢失精度[-fpermissive]&#34;当尝试将char *转换为unsigned int时,就像在原始帖子中所做的那样。 This post解释说应该使用uintptr_t。
答案 2 :(得分:1)
不,它不适用于所有情况。除了可能存在或可能不存在问题的字节顺序之外,您还假设uint32_t
的对齐为4.但此数量是实现定义的(C11草案N1570第6.2.8节)。您可以使用_Alignof
运算符以便携方式进行对齐。
其次,buffer
指向的位置的有效类型(同上。 Sec.6.5)可能与uint32_t
不兼容(例如buffer
}指向unsigned char
数组)。在这种情况下,一旦尝试读取数组本身或通过不同类型的指针,就会破坏严格的别名规则。
假设指针实际指向unsigned char
的数组,则以下代码将起作用
typedef union { unsigned char chr[sizeof(uint32_t)]; uint32_t u32; } conv_t;
void set4Bytes(unsigned char* buffer) {
const uint32_t MASK = 0xffffffffU;
if ((uintptr_t)buffer % _Alignof(uint32_t)) {// misaligned
for (size_t i = 0; i < sizeof(uint32_t); i++) {
buffer[i] = 0xffU;
}
} else { // correct alignment
conv_t *cnv = (conv_t *) buffer;
cnv->u32 = MASK;
}
}
答案 3 :(得分:1)
除了 endian 问题之外,这里已经提到过:
CHAR_BIT
- 每char
的位数 - 也应该考虑。
在大多数平台上都是8,其中for (int i=0; i<4; i++)
应该可以正常工作。
更安全的方式是for (int i=0; i<sizeof(uint32_t); i++)
。
或者,您可以加入<limits.h>
并使用for (int i=0; i<32/CHAR_BIT; i++)
。
答案 4 :(得分:0)
如果您想确保基础数据不“改变形状”,请使用reinterpret_cast<>()
。
正如Learner所提到的,当您将数据存储在机器内存中时, endianess 成为一个因素。如果您知道数据如何在内存中正确存储(正确的字节顺序)并且您专门测试其布局作为替代表示,那么您可能希望使用reinterpret_cast<>()
作为特定类型测试该内存,而无需修改原始存储。
下面,我修改了您的示例以使用reinterpret_cast<>()
:
void set4Bytes(unsigned char* buffer) {
const uint32_t MASK = 0xffffffff;
if (*reinterpret_cast<unsigned int *>(buffer) % 4) {//misaligned
for (int i = 0; i < 4; i++) {
buffer[i] = 0xff;
}
} else {//4-byte alignment
*reinterpret_cast<unsigned int *>(buffer) = MASK;
}
}
还应该注意,您的函数似乎将缓冲区(32字节的连续内存)设置为0xFFFFFFFF,无论它采用哪个分支。
答案 5 :(得分:-1)
您的代码非常适合使用32位及以上的任何架构。字节排序没有问题,因为所有源字节都是0xFF
。
在x86或x64机器上,处理最终未对齐RAM访问所需的额外工作由CPU管理,对程序员是透明的(自Pentium II以来),每次访问都会有一些性能成本。所以,如果你只是设置缓冲区的前四个字节几次,那么你就可以简化你的功能了:
void set4Bytes(unsigned char* buffer) {
const uint32_t MASK = 0xffffffff;
*((uint32_t *)buffer) = MASK;
}
一些读物: