C 代码可以工作,但抛出不兼容的指针类型警告

C 代码可以工作,但抛出不兼容的指针类型警告,c,pointers,casting,avr,8-bit,C,Pointers,Casting,Avr,8 Bit,当我学习C代码时,我想测试一些东西。它按预期工作,但发出了警告 警告1来自不兼容指针类型的分配[由启用] 默认值] 代码很简单。我在这里所做的就是切换atmega2560上的引脚B7。我有一个LED连接到它,我可以看到它闪烁,所以我知道它的工作预期 有人能解释为什么我看到这个错误,即使它是按预期执行的吗? 代码如下: #include <avr/io.h> #include <util/delay.h> void main(void) { int *ptr;

当我学习C代码时,我想测试一些东西。它按预期工作,但发出了警告

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

代码很简单。我在这里所做的就是切换atmega2560上的引脚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);
    }
}
#包括
#包括
真空总管(真空){
int*ptr;
ptr=&PORTB;//此行抛出警告

DDRB=(1编辑2:

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

我的原始答案:

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

ptr = (int*)&PORTB
0x02     5
0x03    11
*(volatile unsigned char *) 0xBEEF
转到
PORTB
的定义,让我们知道它是什么类型

编辑1:

我的假设是您知道
PORTB
是一个
int
,并且您是从
void*
中铸造它的。感谢@H2CO3指出它实际上是一个
(*(volatile uint8_t*)(0x25))
,这基本上意味着
PORTB
是一个
volatile uint8_t

在这种情况下,您不应该将其强制转换为
int
!如果这起作用,则意味着您的机器可能是,您不应该依赖于此

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

我们的记忆中有这样的东西:

Address  Value
0x02        7
0x03       11
注: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
这个例子说明了当我们从指针读取值时会发生什么,那么写呢?让我们保持和以前一样的变量并写一些值

*BytePointer = 5;
现在,内存将如下所示:

ptr = (int*)&PORTB
0x02     5
0x03    11
*(volatile unsigned char *) 0xBEEF
那么
int
指针呢

*IntPointer = 5;
由于
int
是两个字节,它将改变两个字节:

// Little endian
0x02     5
0x03     0

// Big endian
0x02     0
0x03     5
因此,如果您使用
PORTB
作为
int
,每次分配给它时,您都会写入2个字节,一个字节到
PORTB
的地址,一个直接在后面。我希望后面的内容都不重要……您不应该这样做,因此如果您确实想使用指针,应该使用
uint8.

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

int *ptr;
ptr = &PORTB; // This line throws the warning
PORTB
是一种
易失性无符号字符
,定义如下:

ptr = (int*)&PORTB
0x02     5
0x03    11
*(volatile unsigned char *) 0xBEEF
将您的
ptr
声明更改为
易失性无符号字符*

volatile unsigned char *ptr;
ptr = &PORTB;

@荒谬的不,不,不,不,请不要!PORTB
是一个
易失性uint8*
。它是AVR工具链中的一个宏。
int
在AVR平台上有2个字节长。这将把不应该写入的东西写入内存!我查找了PORTB的定义,它是
\u SFR\IO8(0x05)
这是一个用于
\u MMIO\u字节((0x05)+0x20)的宏
这又是一个用于
(*(volatile uint8\u t*)(0x25))的宏
。我将我的
int*ptr
改为
volatile uint8\u t*ptr
,这同样有效。在发布我的问题之前,只需要再深入一点。:)再次感谢!@JoeyvanHummel是的,而且您甚至不需要指针-直接分配到
PORTB
将起作用(出于明显的可读性原因,首选此选项).啊,是的,我同意这一点。我只是测试了一些东西来了解更多信息,但被窃听了,我犯了一个错误,想知道我的错误是什么。不过,谢谢。:@H2CO3是的,你说得很对。我在发布了第一个快速而肮脏的版本后,正在写一个改进的答案。对不起。但是,既然你提到了,我将把这些信息包括在内这就说明了为什么要声明另一个指针是多余的——直接分配给<代码> PORTB将工作得很好。@ H2CO3在这种情况下是肯定的,但他可能想把一个端口作为参数传递给函数,而他必须使用<代码>易失性无符号CHAR*<代码>作为PAR。ameter类型。@ouah-Hmm,你的答案肯定比我原来的帖子更正确,在我修复它的时候,你已经有了这个。我已经引用了你,我也会更新你的答案。