2016-11-17 66 views
1

我正在研究一些C程序,最近我有这个困惑,再次打我: 假设我有一个函数需要一个32位大小的变量,另一个需要8位,我们必须将数据从32位变量传送到8位变量。不同数据类型的大小导致混淆

这里是我与混乱的一个范例程序:

#include <stdio.h> 
#define SIZE_OF_BLOCK 512 
uint32* a = NULL; // for read 
uint8* b = NULL; // for write 

int read_register(uint32* rbuff) 
{ 
    uint8 i; 
    for (i = 0; i < SIZE_OF_BLOCK/4; i++) // here one 
     rbuff[i] = read_from_32_bit_reg(); // read incrementally on each iteration 
    return 0; 
} 

int write_register(uint8* wbuff) 
{ 
    uint8 i; 
    for (i = 0; i < SIZE_OF_BLOCK; i++) // here one 
     write_reg(wbuff[i]);   // point 2 
    return 0; 
} 

int main() 
{ 
    a = (uint32*)malloc(sizeof(uint32) * 128); // contains 4096 bits 
    b = (uint8*)malloc(sizeof(uint8) * 512); // contains 4096 bits 
    read_register(a); 
    b = (uint8*)a; // point 1 
    write(0x0080000, b); 
    free(a); 
    free(b); 
    return 0; 
} 

1)因此,我得到的所有512个比特在128中,4字节的位置。如果我将这个值赋给一个8位的位置,我将剥掉哪一个位? MSB 8位或者Intel PC上的LSB 8位。

2)我仍然在传输4096位,'b'的地址是a的寻址位置。我是否仍然在传输所有正确的值?

它基本上是一个混乱,不能下定决心,如何接近它。

P.S.该术语被称为缩小,但如果我按照我所做的相同的方式进行操作,将32位变量的地址分配给8位变量,并以8位增量进行操作,它应该能够获得所有值?我不认为缩小发生在指针变量的情况下,因为两者都是int大小?

+0

[将大量类型转换为更小类型]可能的副本(http://stackoverflow.com/questions/6752567/casting-a-large-number-type-to-a-smaller-type) –

+0

In指针的情况下它是如何相同的? –

+1

32 * 128不是512位,它是512字节。 – stark

回答

0

如果我得到了正确的问题,并且您问32位无符号整型变量分配给8位无符号整型变量会发生什么?

这称为缩小,结果将是最小的无符号值等于源值模2n其中n是用于表示目标类型的位数。这与表示的字节顺序无关,因为它被定义为算术结果,它在每个平台上都是相同的。

+0

所以,如果我做的事情一样,像我一样,从32位变量分配的地址,到8位变量,经过8位的增量,应该能够得到所有的值? –

+0

目前尚不清楚OP是否在询问有关情况。在他的代码中,他使用指向'uint8_t'的指针访问'uint32_t'数组。这并没有缩小,它具有**所有与排序问题有关的事情。存储'uint32_t'成'uint8_t'变量是好的,但通过不同的类型访问该阵列具有非常不同的影响。 – chqrlie

2

首先一句话:当您使用

a = (uint32 *)malloc(sizeof(uint32)*128);//contains 512 bits 

你就错了:你应该写...//contains 512 bytes

然后,你必须从整型一种尺寸的传球到的两种方式更小的尺寸:

  • 通过转化:

    uint32_t a = 259; 
    uint8_t b = a; // perfectly defined for unsigned types: retains the low order bits here 3 
    

    正式为C99标准中的n1256草案说:

    否则,如果新类型是无符号的,所述值是通过反复增加或 减去比可在表示的最大值多一个转换新型 直到该值是在新的类型

  • 的范围由混叠(类型双关):

    uint32_t a = 259; 
    uint8_t b = *((uint8_t) &a); // LSB on Intel so 3 but 0 on a big endian system 
    

    指向任何对象的指针总是可以转换为指向char(或unsigned char)的指针。由于uint8_t只能是unsigned char(*),所以指针转换是有效的,并且将按顺序返回uint32_t的表示的所有字节...其值为实现依赖于。英特尔PC通常使用2的补小端架构,所以你会得到LSB,仍然3。但是,这将是大端架构中的MSB(0)。

    但在一般情况下,访问一个类型的值与非兼容的类型是未定义行为意味着编译器可以自由地做任何事情,包括注释掉的那一行!

现在为您点1和2。1,你的指针分配到的uint32_t数组的指针uint8_t。这是完全有效的。在2您使用uint8_t指针来访问所有的原始阵列的uint32_t值的表示的字节。它仍然是完全有效的,你可以从字节中重建原始值,但字节值本身是依赖于实现的。

最后一个要说无关的问题:当你将通过malloc到一个新的值所获得的指针,但不保存或第一释放它,你失去所有的可能性,后来免费了,导致内存泄露。在这里,您有:

b = (uint8 *)malloc(sizeof(uint8)*512);//contains 512 bits 
... 
b = (uint8 *)a;// memory leak! 

(*)一char需要能够代表ASCII字母的所有值,所以它需要至少7位和所有类型的大小必须属于char多尺寸。所以,如果一个uint8_t类型存在,它必须是unsigned char的代名词。

+0

@chux:这样更好:-)谢谢! –