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

Joe*_*mel 4 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

oua*_*uah 9

int *ptr;
ptr = &PORTB; // This line throws the warning
Run Code Online (Sandbox Code Playgroud)

PORTB是这样的volatile unsigned char定义:

*(volatile unsigned char *) 0xBEEF
Run Code Online (Sandbox Code Playgroud)

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

volatile unsigned char *ptr;
ptr = &PORTB;
Run Code Online (Sandbox Code Playgroud)


non*_*kle 5

PORTB可能没有被定义为int这意味着当你拿走你的地址时PORTB就不会得到一个int *.如果您确定自己是正确的并且可以使用int *for PORTB,则可以使用强制转换来告诉编译器它不需要担心.你可以这样投:

ptr = (int*)&PORTB
Run Code Online (Sandbox Code Playgroud)

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

编辑2:

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

编辑1:

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

在这种情况下,你永远不应该把它投到一个int!如果这有效,则意味着您的机器可能是小端,您不应该依赖于此.

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

我们在记忆中有这个:

Address  Value
0x02        7
0x03       11
Run Code Online (Sandbox Code Playgroud)

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

现在我们有两个指针:

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
Run Code Online (Sandbox Code Playgroud)

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

*BytePointer = 5;
Run Code Online (Sandbox Code Playgroud)

内存现在看起来像这样:

0x02     5
0x03    11
Run Code Online (Sandbox Code Playgroud)

int指针怎么样?

*IntPointer = 5;
Run Code Online (Sandbox Code Playgroud)

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

// Little endian
0x02     5
0x03     0

// Big endian
0x02     0
0x03     5
Run Code Online (Sandbox Code Playgroud)

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

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

  • @nonsensical NAH NO NO NO PLEASE***NOOOOOO!***`PORTB`是一个`volatile uint8_t*`.它是AVR工具链中的一个宏.`int`在AVR平台上长2个字节.这会将内容写入内存,它不应该写入! (2认同)