Арифметика странного указателя в цикле for в C
Я программирую msp430 с IAR EBW.
Я получил выражение следующим образом:
adres = (uint_fast16_t *) 0x8602 + (0x0200*i);
в цикле, так что я увеличивается с каждым циклом. По какой-то причине он пропускает каждый из двух адресов и дает мне:
0x8602
0x8A02
0x8E02
и так далее. Таким образом, 0x8802 пропускается, как 0x8C02 и так далее.
Почему это происходит?
//// ниже приведен полный код, обратите внимание, что я размещен в трех циклах, и каждый дает одинаковый результат. //// отметим также, что при проверке во время отладки он показывает как: 1,2,3... и т. д.
#include "io430.h"
#include <stdint.h>
int main( void )
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
// Inicjalizuj piny GPIO
P3OUT &= ~(BIT4+BIT5); // zeruj wartości by zapobiec krótkotrwałym impulsom
P3DIR |= BIT4; // ustaw pin3.4 UCA0TXD oraz piny 3.0 CS, 3.1 SIMO, 3.3 CLK jako wyjście
P3DIR &= ~(BIT5); // ustaw pin3.5 UCA0RXD oraz 3.2SOMI jako wejście
P3SEL |= BIT4+BIT5; // daj funkcje TXD i RXD pinom 3.4 i 3.5, funkcje SIMO,SOMI,CLK pinom 3.1,3.2,3.3
// Inicjalizuj ustawienia zegarów BCS
BCSCTL1 = CALBC1_16MHZ; // ustawia DCO na 16MHz, wyłącz XT2, LFXT1 w trybie niskiej częstotliwości
DCOCTL = CALDCO_16MHZ; // ustawia DCO na 16MHz
BCSCTL2 |= BIT2; // ustawia dzielnik SMCLK na 4
// Ustaw flash na czyszczenie segmentów
while(FCTL3&BIT0); // czekaj aż będzie można inicjalizować
FCTL2 = FWKEY + BIT6 + BIT5+BIT3+BIT2; // ustawia źródło zegara na MCLK oraz jego dzielnik dający f = 363 kHz
FCTL1 = FWKEY + BIT1; // czyść indywidualne segmenty
FCTL3 = FWKEY; // zdejmuje blokadę na pisanie i czyszczenie (tu segmentów)
// Czyść segmenty
uint_fast16_t *adres;
uint_fast8_t i=0;
for ( i=0 ; i < 59; i++)
{
adres = (uint_fast16_t *) 0x8602 + i*0x0200; // ustawia wskaźnik na kolejne miejsa w pamięci. sprawdzić!!
*adres = 0; // wyczyść segment przez wpisanie w jego komórkę głupiego bitu
while(FCTL3&BIT0); // poczekaj aż generator czasowy dla flasha
}
FCTL1 = FWKEY; // blokuje możliwość czyszczenia
__delay_cycles(65000);
// Ustaw flash na zapis danych
while(FCTL3&BIT0); // czekaj aż będzie można pisać
FCTL1 = FWKEY + BIT6; // pozwól pisać do flash
// Pisz do flash
uint_fast16_t szesnastka = 0;
for ( i=0 ; i < 59; i++)
{
szesnastka = (0x55 << 8 ) | 0xF0;
adres = (uint_fast16_t *) 0x8602 + (0x0200*i); // ustawia wskaźnik na kolejne miejsa w pamięci. sprawdzić!!
*adres = szesnastka; // wyczyść segment przez wpisanie w jego komórkę głupiego bitu
while(FCTL3&BIT0); // poczekaj aż generator czasowy dla flasha
}
FCTL1 = FWKEY; // blokuje możliwość pisania
FCTL3 = FWKEY + LOCK; // ustawia blokadę na pisanie i czyszczenie
__delay_cycles(65000);
// Inicjalizuj ustawienia do transmisji UART
UCA0CTL0 = 0x00; // ustawia domyślne parametry protokołu
UCA0CTL1 |= BIT7+BIT6; // ustawia źródło sygnału na SMCLK
UCA0BR0 = 0xA0; // ustawia dzielnik 4MHz do baud rate 9600
UCA0BR1 = 0x01; // ustawia dzielnik 4MHz do baud rate 9600
UCA0MCTL |= BIT2+BIT3; // ustawia modulacje zegara do baud rate 9600
UCA0CTL1 &= ~UCSWRST; // włącza maszynę USCI
uint8_t *ptr;
// Wyślij wszystkie wyniki poprzez UART
for( i=0 ; i < 59 ; i++ )
{
ptr = (uint8_t *) 0x8602 + i*0x0200; // ustawia wskaźnik na kolejne miejsa w pamięci.
while(!(IFG2&UCA0TXIFG)); // czeka na możliwość wysłania
UCA0TXBUF = *ptr; // wysyła dane przez UART
ptr++;
while(!(IFG2&UCA0TXIFG)); // czeka na możliwość wysłania
UCA0TXBUF = *ptr; // wysyła dane przez UART
}
return 0;
}
4 ответа
Вы приводите первое значение как указатель к 16-битным значениям, поэтому добавление 0x200
собирается переместить его вперед на 512 16-битных (или 2-байтовых) значений.
Если вы сделали:
adres = (uint_fast32_t *) 0x8602 + (0x0200 * i ) ;
Это сделало бы:
0x8602
0x8E02
0x9202
Либо масштабируйся наполовину, либо делай математику перед броском:
adres = ( uint_fast16_t *) ( 0x8602 + ( 0x0200 * i ) ) ;
Это арифметика указателей, а не целочисленная математика.
Как i
приращения, (uint_fast16_t *) 0x8602 + (0x0200*i)
идет вверх 0x0200*2
как sizeof(uint_fast16_)
в данном случае - 2.
Когда вы добавляете указатель, вы добавляете размер типа указателя к указателю, с которым вы работаете. Так, например, добавив 1 к char*
добавит 1, и добавив 1 к uint32_t*
добавлю 4.
Поэтому я думаю, что ваш код может работать так, как вы ожидаете, если вы измените его на:
adres = (uint_fast16_t *) ((char*)0x8602 + (0x0200*i));
Вы увеличиваете указатель uint_fast16* на 0x0200*i.
Когда вы добавляете к указателю, он увеличивается на размер базового типа, так что вы увеличиваете на 2 байта * 0x0200*i, а не только 0x0200 * i