代码有效,但抛出不兼容的指针类型警告

时间:2013-07-14 21:51:16

标签: c pointers casting avr 8-bit

在学习C代码时尝试一下,我想测试一下。它按预期工作,但抛出警告

  

警告1来自不兼容指针类型的分配[启用   默认]

代码很简单。我在这里所做的就是在atmega2560上切换PIN B7。我有一个LED挂钩,我可以看到它闪烁,所以我知道它按预期工作。

有人可以解释为什么我看到这个错误,即使它按预期执行了吗? 代码如下:

#include <avr/io.h>
#include <util/delay.h>

void main(void) {
    int *ptr;
    ptr = &PORTB; // This line throws the warning

    DDRB = (1 << 7);

    while(1) {
        *ptr = (1 << 7);
        _delay_ms(1000);

        *ptr = (0 << 7);
        _delay_ms(1000);
    }
}

PORTB是一个8位寄存器,每个引脚有一位用于控制该引脚是高电平还是低电平。

现在,我很高兴它有效。但是这些警告让我烦恼。

2 个答案:

答案 0 :(得分:9)

int *ptr;
ptr = &PORTB; // This line throws the warning

PORTBvolatile unsigned char定义的类似内容:

*(volatile unsigned char *) 0xBEEF

将您的ptr声明更改为volatile unsigned char *

volatile unsigned char *ptr;
ptr = &PORTB;

答案 1 :(得分:5)

PORTB可能未被定义为int,这意味着当您获取PORTB的地址时,您将无法获得int *。如果您确定自己是正确的并且可以使用int *作为PORTB,则可以使用强制转换来告诉编译器它不需要担心。你可以像这样投射:

ptr = (int*)&PORTB

转到PORTB的定义,让我们知道它是什么类型。

编辑2:

我已经写了一个解释为什么你不应该使用我上面的答案,当我到处纠正它时,我发现@ouah已经发布了正确答案所以我请你用它而不是我的。有关原因的解释,请阅读下面的编辑1

修改1:

我的假设是您知道PORTBint并且您是从void*投出来的。感谢@ H2CO3指出它实际上是(*(volatile uint8_t *)(0x25)),这基本上意味着PORTBvolatile uint8_t

在这种情况下,你永远不应该把它投到int!如果这有效,则意味着您的机器可能是little endian,您不应该依赖它。

为了正确解释,我们设置一个简单的例子:

我们在记忆中有这个:

Address  Value
0x02        7
0x03       11

注意:7为十六进制0x07,二进制为00000111,十六进制为11 0x0B,二进制为00001011

现在我们有2个指针:

uint8_t* BytePointer;
int*     IntPointer; // int is either 2 or 4 bytes, we will assume it is 2 bytes.
int Value16;
uint8_t Value8;

// Let's set both to point to our fake memory address
BytePointer = (uint8_t*) 0x02;
IntPointer  = (int*)     0x02;

// Now let's see what value each holds?
Value8 = *BytePointer;
Value16 = *IntPointer;

// Value8 will contain 0x07
// Value16 will contain 0x0B07 on a Little Endian machine
// Value16 will contain 0x070B on a Big Endian Machine

这个例子说明当我们从指针读取值时会发生什么,怎么办?让我们保持与以前相同的变量并写一些值

*BytePointer = 5;

内存现在看起来像这样:

0x02     5
0x03    11

int指针怎么样?

*IntPointer = 5;

由于int是两个字节,它将改变两个字节:

// Little endian
0x02     5
0x03     0

// Big endian
0x02     0
0x03     5

因此,如果您使用PORTB作为int,则每次分配给它时,您将写入2个字节,一个写入PORTB的地址,然后一个写入。我希望无论什么事情都不重要......你不应该这样做,所以如果你真的想使用指针,你应该使用uint8_t*

但是当我开始正确地解释它时,@ ahah已经发布了正确的答案。请参考它如何做到这一点。