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 は、そのピンが HIGH か LOW かを制御するためにピンごとにビットを持つ 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はおそらく として定義されていません。intこれは、 のアドレスをPORTB取得しても が得られないことを意味しますint *。あなたが正しく、int *forPORTBを使用できると確信している場合は、キャストを使用して、心配する必要がないことをコンパイラーに伝えることができます。次のようにキャストできます。

ptr = (int*)&PORTB

の定義に移動し、PORTBそれがどのタイプであるかをお知らせください。

編集1:

PORTB私は、それが であることを知っていてint、 からキャストしていると仮定しましたvoid*。@H2CO3 さん、実際には a であることを指摘していただき、ありがとうござい(*(volatile uint8_t *)(0x25))ます。PORTBvolatile uint8_t

これは、絶対にキャストしないでくださいint。これが機能する場合は、マシンがおそらくリトルエンディアンであり、これに頼るべきではないことを意味します。

適切に説明するために、簡単な例を設定しましょう。

これは記憶に残っています:

Address  Value
0x02        7
0x03       11

注: 7 は 16 進数で 0x07、2 進数で 00000111、11 は 16 進数で 0x0B、2 進数で 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は 2 バイトであるため、2 バイトが変更されます。

// Little endian
0x02     5
0x03     0

// Big endian
0x02     0
0x03     5

したがって、PORTBとして使用するとint、それに割り当てるたびに のアドレスに 1 バイト、PORTB直後に 1 バイトの 2 バイトが書き込まれます。後が重要ではないことを願っています...これを行うべきではないので、uint8_t*本当にポインターを使用したい場合はを使用する必要があります。

しかし、私がそれをすべて適切に説明するまでに、@ouahはすでに正解を投稿しています. これをどのように行うべきかについては、それを参照してください。

于 2013-07-14T21:52:21.883 に答える