4

当我学习 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 位寄存器,每个引脚都有一个位来控制该引脚是高电平还是低电平。

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

4

2 回答 2

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

PORTB是这样volatile unsigned char定义的:

*(volatile unsigned char *) 0xBEEF

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

volatile unsigned char *ptr;
ptr = &PORTB;
于 2013-07-14T21:58:26.313 回答
6

编辑2:

当我开始纠正我的原始答案(如下)时,我看到@ouah 已经发布了一个正确的答案,所以我请你使用它而不是我的。有关更详细的说明,请阅读下面的“编辑 1”

我原来的答案:

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

ptr = (int*)&PORTB

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

编辑1:

我的假设是你知道那PORTB是一个int并且你是从void*. 感谢@H2CO3 指出它实际上是 a(*(volatile uint8_t *)(0x25))基本上意味着它PORTB是 a volatile uint8_t

在这种情况下,您永远不应该将其转换为int! 如果这可行,则意味着您的机器可能是小端,您不应该依赖它。

为了正确解释它,让我们建立一个简单的例子:

我们在内存中有这个:

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;

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

// Little endian
0x02     5
0x03     0

// Big endian
0x02     0
0x03     5

因此,如果您使用PORTBas int,则每次分配给它时,您都在写入 2 个字节,一个写入地址,PORTB一个紧接在其后。我希望之后的一切都不重要......你不应该这样做,所以uint8_t*如果你真的想使用指针,你应该使用 an 。

但是当我开始正确解释这一切时,@ouah 已经发布了一个正确的答案。请参阅它以了解如何执行此操作。

于 2013-07-14T21:52:21.883 回答