2013-07-14 50 views
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位寄存器。

現在,我很高興它的工作原理。但是這些警告令我煩惱。

回答

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

值得一提的是,這就是爲什麼聲明另一個指針是多餘的原因 - 直接賦值給'PORTB'將會工作得很好。 – 2013-07-14 21:59:31

+0

@ H2CO3在這種情況下是的,但他可能希望將端口作爲參數傳遞給函數,並且他必須使用'volatile unsigned char *'作爲參數類型。 – ouah

+0

@ouah嗯,你的答案肯定比我原來的帖子更正確,當我修好它的時候,你已經有了這個。我引用了你,我也會贊成你的答案。 – nonsensickle

5

PORTB可能未被定義爲int這意味着當您將地址PORTB時,您將不會得到int *。如果你確定你是對的,那麼你可以使用int *代替PORTB,你可以使用轉換來告訴編譯器它不需要擔心。你可以施放它是這樣的:

ptr = (int*)&PORTB 

去的PORTB的定義,讓我們知道它是什麼類型。

編輯2:

我寫的,爲什麼你不應該用我上面的答案的解釋,並通過我身邊糾正它的時候我看到@ouah已經發佈一個正確的答案,所以我請你請使用它,而不是我的。有關爲什麼的解釋,請閱讀下面的我的編輯1

編輯1:

我的假設是,你知道PORTB是一個int和你是從void*鑄造它。感謝@ H2CO3指出它實際上是(*(volatile uint8_t *)(0x25)),這基本上意味着PORTBvolatile uint8_t

這種情況下,你應該永遠不要投它到int!如果這個工作,這意味着你的機器可能是little endian,你不應該依賴這個。

爲了解釋得當,讓我們建立一個簡單的例子:

我們有這樣的記憶:

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; 

內存現在看起來是這樣的:

0x02  5 
0x03 11 

什麼的int指針?

*IntPointer = 5; 

由於一個int是兩個字節,它會改變兩個字節:

// Little endian 
0x02  5 
0x03  0 

// Big endian 
0x02  0 
0x03  5 

所以如果你使用PORTBint,每次分配給它,你正在寫2個字節,一到時間地址PORTB和一個後續。我希望以後的任何事情都不重要......你不應該這樣做,所以如果你真的想使用指針,你應該使用uint8_t*

但是,當我開始解釋這一切正確的@ouah已經發布了一個正確的答案。請參考它應該如何完成。

+0

這就是它!非常感謝你:) –

+2

@nonsensical NAH NO NO NO PLEASE *** NOOOOOO!***'PORTB'是一個'volatile uint8_t *'。這是來自AVR工具鏈的宏。 AVR平臺上的「int」長度爲2個字節。這會將東西寫入記憶中,它不應該寫入! – 2013-07-14 21:58:04

+1

我查找了'_SFR_IO8(0x05)'PORTB的定義,它是'_MMIO_BYTE((0x05)+ 0x20)'的宏,而宏又是'(*(volatile uint8_t *)(0x25) '。 我把我的'int * ptr'改成了'volatile uint8_t * ptr',這也適用。 在發佈我的問題之前,只好深入一點。 :) 再次感謝! –

相關問題