不同数据类型的大小会引起混淆

时间:2016-11-17 18:40:33

标签: c

我正在研究一些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)所以我得到128位,4字节位置的所有512位。如果我将这个值分配给一个8位的位置,我正在剥离哪一位?英特尔PC上的MSB 8位或LSB 8位。

2)我仍然传输4096位,'b'具有寻址位置的地址。我还在转移所有正确的值吗?

它基本上是一种混乱,无法下定决心,如何接近它。

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

2 个答案:

答案 0 :(得分: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)。

    但是在一般情况下,访问具有非兼容类型的一种类型的值是Undefined Behavior,这意味着编译器可以自由地执行任何操作,包括注释掉有问题的行!

现在为您的第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的同义词。

答案 1 :(得分:0)

如果我的问题是正确的,那么你问的是当32位无符号整数变量被分配给8位无符号整数变量时会发生什么?

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