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位寄存器,每个引脚有一位用于控制该引脚是高电平还是低电平.
现在,我很高兴它有效.但这些警告让我烦恼.
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)
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)
因此,如果您使用PORTB
它int
,每次分配给它时,您将写入2个字节,一个写入地址,一个写入PORTB
.我希望无论什么事情都不重要......你不应该这样做,所以你应该使用一个uint8_t*
如果你真的想使用指针.
但当我开始正确地解释它时,@ ahah已经发布了正确答案.请参考它如何做到这一点.