Aktyw Forum

Zarejestruj się na forum.ep.com.pl i zgłoś swój akces do Aktywu Forum. Jeśli jesteś już zarejestrowany wystarczy, że się zalogujesz.

Sprawdź punkty Zarejestruj się

Tablice i wskaźniki w C++

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:
Tablice i wskaźniki w C++

Postautor: Sławek5 » 21 wrz 2005, o 05:37

Witajcie.
Prosiłbym Was o pomoc w zrozumienu 2 rzeczy w sprawie tablic i wskaźników.

1. Jeżeli mam tablicę jedna zadeklarowaną jako char code tablica1[3]; oraz drugą char tablica2[3]; to jak jest ze wskaźnikam i deklaracją tych wskaźników, bo spotkałem 2 różne deklaracje sprzecne ze sobą. Czy wskaźnik do talica1 ma być dekarowany jako "char code *ptr1", a do tablica 2 jako "char *ptr2", czy jeszcze jakoś inaczej.

2.Sprawa dotyczy przekazywania tych wskażników do funkcji.
Tzn. mam dwa łańcuchy pierszy char code lancuch1[]="lancuch"; oraz drugi w RAM char lancuch2[]="lancuch";
Jeżeli jest teraz funkcja void test( char *ptr); to jak do niej przesłać te dwie tablice, a może jakoś inaczej ją zadeklarować.

Sławek.

Guru
-
-
Posty:250
Rejestracja:30 cze 2003, o 13:26
Lokalizacja:Kraków

Postautor: Guru » 21 wrz 2005, o 06:52

Zacznijmy może od tego, że gdy stosujesz słowo kluczowe "code" to raczej nie jest to C++ a tylko "C". Wskaźnik do tablicy to miejsce w pamięci, które dynamicznie będziemy zmieniać wskazując na te czy inne obiekty. Nie wiem jak tam twój kompilator, ale chyba nie można deklarować wskaźnika jako "code" czyli umieszczjąc go w pamięci przeznaczonej dla kodu programu.
Jeżeli chodzi o inicjalizację wskaźnika do tablicy to można zrobić to na dwa sposoby:
char *wsk = tablica;
lub
char *wsk = &tablica[0];

Jak do funkcji przesłać łańcuch? No więc w przypadku twojej funkcji można przesłać oba łańcuchy w jednakowy sposób czyli:
test(lancuch1);
lub
test(lancuch2);

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 21 wrz 2005, o 10:06

Kompilator Raisonance RC-51, a także KEIL przyjmują watości code i takie są używane nawet w ksiżżce pana Jacka Bogusza z wydawnictwa BTC.
Druga rzecz to jak to jest jeżeli nie ma tablicy tylko przekazujemy daną zadeklarowaną jako np. char DANA; a funkcja jest jako void funkcja(char *ptr); czy można do takiej funkcji przekazac te dwie dane i jak tzn. talice zadeklarowana char code tablica[9]; oraz char DANA;
Oczywiscie DANA jest w RAM a talica we FLASH MEMORY.

a_antoniak
-
-
Posty:651
Rejestracja:13 sty 2005, o 18:38
Lokalizacja:Krasnystaw
Kontaktowanie:

Postautor: a_antoniak » 21 wrz 2005, o 14:48

A po co przekazywać daną typu char do funkcji z argumrntem typu char* ?

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 21 wrz 2005, o 15:45

Potrzebuję funkcji, która przyjmuje parametryz tablic zarówno z pamieci ram jak i z pamieci programu np tablice we flash

a_antoniak
-
-
Posty:651
Rejestracja:13 sty 2005, o 18:38
Lokalizacja:Krasnystaw
Kontaktowanie:

Postautor: a_antoniak » 21 wrz 2005, o 16:36

Sprawa zależy od kompilatora. Niekiedy problem nie leży w tym jak przekazać parametry, a w tym jak "dobrać się" do zawartości tablic we wnętrzu funkcji. Funkcja określona następująco:

void Fun(char* chPtr);

przyjmie wskaźniki do tablic zarówno umieszczonych we Flash-u jak i w RAMie. Ale w jej wnętrzu trzeba się inaczej z nimi obchodzić, po prostu dlatego że inne instrukcje asemblera używane są do odczytu danych z RAMu a inne z Flasha. Tak jest np. w AVR-GCC.

A niekiedy jest tak, że kompilator sam zapewnia odpowiedni dostęp jeśli ma w nagłówku funkcji informacje o tym czy wskaźnik odołuje się do RAMu czy do Flasha. Wtedy ciało funkcji może wyglądać tak samo, ale jest inaczej kompilowane bo w headerze jest informacja o rodzaju pamięci do jakiej odwołujesz się przez wskaźnik. Tak jest np. w kompilatorze Tasking51.

Popróbuj. Ale wygląda na to, że jednej uniwersalnej funkji mieć nie będziesz. W momencie kompilacji kompilator MUSI wiedzieć jak odwoływać się do pamięci w jej ciele (jakimi instr. assemblera). Jego wiedza na ten temat pochodzi albo z nagłówka funkcji albo z jej ciała.

Guru
-
-
Posty:250
Rejestracja:30 cze 2003, o 13:26
Lokalizacja:Kraków

Postautor: Guru » 22 wrz 2005, o 06:25

Ja korzystam z SDCC i nie muszę się martwić czy wskaźnik odołuje się do RAMu czy do Flasha, kompilator sam sobie z tym świetnie radzi. Czyli jedna procedura na oba przypadki, ponieważ SDCC oprócz samego wskaźnika czyli adresu do tablicy przekazuje też typ wskaźnika, podejrzewam, że większość kompilatorów tak robi.
Co do deklaracji typu:
code char *wsk;
to mam ogromne wątpliwości, bo procedura inicjująca wskaźnik
wsk = &costam;
musiała by zapisać tą informację w pamięci programu, czyli dla danego procesora tylko z pamięcią flash ew. mogło by to działać, ale gdy program będzie w pamięci EPROM to co wtedy. Z tego co się orientuję to zapis do pamięci Flash jest też odmienny od zapisu do RAMu, no więc deklaracją
code char *wsk;
tworzymy stały wskaźnik do stałego typu a nie o to chodzi we wskaźnikach.

a_antoniak
-
-
Posty:651
Rejestracja:13 sty 2005, o 18:38
Lokalizacja:Krasnystaw
Kontaktowanie:

Postautor: a_antoniak » 22 wrz 2005, o 07:52

Ja korzystam z SDCC i nie muszę się martwić czy wskaźnik odołuje się do RAMu czy do Flasha, kompilator sam sobie z tym świetnie radzi. Czyli jedna procedura na oba przypadki, ponieważ SDCC oprócz samego wskaźnika czyli adresu do tablicy przekazuje też typ wskaźnika, podejrzewam, że większość kompilatorów tak robi.
Jeśli SDCC (nie korzystałem) tak robi to miło.
Swoja drogą: właśnie przejżałem swój stary program na '51 napisany pod Raisonance i wygląd na to, że uniwersalna proc. powinna jednak działać. Ale ręki sobie uciąć nie dam :)
Co do deklaracji typu:
code char *wsk;
to mam ogromne wątpliwości, bo procedura inicjująca wskaźnik
wsk = &costam;
musiała by zapisać tą informację w pamięci programu,
Wystarczy, że kompilator sprawdzi czy costam umieszczone jest w pamięci programu. Taką informację ma w deklaracji. Sławkowi proponuję zrobienie kiku prostych eksperymentów i podzielenie się wynikami na forum.
czyli dla danego procesora tylko z pamięcią flash ew. mogło by to działać, ale gdy program będzie w pamięci EPROM to co wtedy.
Program w pamięci EPROM? Juz nie te czasy... :D
Z tego co się orientuję to zapis do pamięci Flash jest też odmienny od zapisu do RAMu, no więc deklaracją
code char *wsk;
tworzymy stały wskaźnik do stałego typu a nie o to chodzi we wskaźnikach.
Jaki stały wskaźnik? Raczej wskaźnik do stałej, a to co innego. Możemy z grubsza potraktować formalnie przydomek code jako ekwiwalent const ze względu na charakter pamięci programu (niemodyfikowalność , przynajmniej nie prosta) - chyba :).

Guru
-
-
Posty:250
Rejestracja:30 cze 2003, o 13:26
Lokalizacja:Kraków

Postautor: Guru » 22 wrz 2005, o 14:13

EPROM Epromem, ale C jest wieczny :)

Pisząc stały wskaźnik do stałej miałem na myśli wskaźnik którym nie da się poruszać, (czyli rzeczywiście odpowiednik const) a jeśli dodamy do tego, że będzie wskazywał na początek tablicy w pamięci programu to niestety będzie to wskaźnik do stałej czyli

const char *const wsk

Do a_antoniak

Guru napisał:
Co do deklaracji typu:
code char *wsk;
to mam ogromne wątpliwości, bo procedura inicjująca wskaźnik
wsk = &costam;
musiała by zapisać tą informację w pamięci programu,


Wystarczy, że kompilator sprawdzi czy costam umieszczone jest w pamięci programu. Taką informację ma w deklaracji. Sławkowi proponuję zrobienie kiku prostych eksperymentów i podzielenie się wynikami na forum.


Ale kompilator w przypadku procedury wsk = &costam wyciąga adres do costam i costam może być "code" natomiast gorzej jeżeli wsk jest "code" co oznacza że do niego nie zapiszemy.
Ostatnio zmieniony 23 wrz 2005, o 05:56 przez Guru, łącznie zmieniany 1 raz.

a_antoniak
-
-
Posty:651
Rejestracja:13 sty 2005, o 18:38
Lokalizacja:Krasnystaw
Kontaktowanie:

Postautor: a_antoniak » 22 wrz 2005, o 16:51

Wskaźnikiem do stałej da się poruszać.

Nie da się poruszać stałym wskaźnikiem - to nie to samo!

W stałym wskaźniku chodzi o to że wskazuje na stałe miejsce w pamięci i nie da się nim poruszać. Ale wskazywane dane można zmieniać za jego pomocą.
Inaczej jest w przypadku wskaźnika do stałej. Da się nim poruszać, ale nie da się za jego pomocą zmieniać wskazywanych danych.

Więc jeśli code char *ptr rzeczywiści można traktować jako wskaźnik do stałej, to poruszać nim się jak najbardziej da. Z tego co pamiętam w kompilatorze Tasking51 trzeba było w headerze funkcji deklarować tak wskaźnik aby odwoływać się do Flash-a. Tyle że tam słówko (modyfikator) było _rom a nie code.


const char *ptr - wsk. do stałej
char *const ptr - stały wskaźnik

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 23 wrz 2005, o 04:02

Podam przykład o co mi mniej więcej chodzi.

Deklaracje:
char tab_1[5]={1,2,3,4,5};
char code tab_2[4]={6,7,8,9};

char dana;


mam funkcję:

void funkcja (char *ptr)
{
//np

P3= *ptr; //czy to jest dobrze czy P3=ptr;
}



oraz w program główny:

main()
{

//podstawiam

funkcja(tab_1);

funkcja (tab_2);

funkcja(dana); //czy to jest poprawne?

funkcja('A'); //litera A czy też jest ok?
}


czy takie wywołania są poprawne??

Guru
-
-
Posty:250
Rejestracja:30 cze 2003, o 13:26
Lokalizacja:Kraków

Postautor: Guru » 23 wrz 2005, o 06:08

Myślę że należy rozgraniczyć tutaj deklaracje
code char*wsk;
i
const char*wsk;
bo code i const to nie to samo, w przypadku 8051 i klonów gdzie rozgraniczona (czyt. inaczej obsługiwana) jest pamięć programu i danych słowo code nakazuje umieszczenie tego co znajduje się za nim w pamięci programu, natomiast const mówi "nie ruszaj" i nie zwraca uwagi gdzie jest zmienna czy wskaźnik (w pamięci programu czy też danych), poprostu "nie ruszaj" i już.

W przypadku SDCC deklaracja code char *wsk_c; umieszcza deklarowany wskaźnik w pamięci programu i po sprawie, czyli: char *const wsk;
a jeżeli to jest wskaźnik do tablicy, która też jest w "code" to const char* const wsk;

A co do programu powyżej to nie są poprawne wywołania:

funkcja(dana); //czy to jest poprawne?
funkcja('A'); //litera A czy też jest ok?

dana jest typu char, 'A' też jest typu char
czyli aby wywołać funkcję z tymi parametrami należy zrobić tak:
char *wsk;
wsk = &dana;
lub dana = 'A';
wsk = &dana;

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 23 wrz 2005, o 15:10

Chciałem si podzielić moimi doświadczeniami.

Jeżeli mam funkcję:
void funkcja(char *ptr)
{
P3=*ptr; //np
}


a w funkcji main:

main()
{

char code tab1[]={1,2,3,4}; //tabela we flash

char tab2[]={6,7,8}; //tabea w ram


teraz:

funkcja(tab1); //lub funkcja(&tab1[0]);
//nastepnie
funkcja(tab2); //lub funkcja(&tab2[0]);

powoduje pojawienie sie na P3 tego co jest na pierwszym miejscu w tablicy.

Sprawdzałem jak jest to przetłumaczone na ASM i w zależności od tego który wskaźnik przesyamy w ram czy flash to w rednym z rejestrów jest przekazywana informacja odnośnie tego.


dzała jeszcze takie wywałanie:
funkcja("A");
na P3 pojawia sie 61 czyli odpowiednik duzej litery a
Natomiast nie działa
funkcja('A'); //tzn apostrofem


i nie wiem dlaczego?
Jak macie jakieś uwagi to piszcie.

Sławek.

a_antoniak
-
-
Posty:651
Rejestracja:13 sty 2005, o 18:38
Lokalizacja:Krasnystaw
Kontaktowanie:

Postautor: a_antoniak » 23 wrz 2005, o 17:14

Czyli wygląda na to, że uniwersalna funkcja wypala :)


Co do wywołania z "A" i z 'A':

"A" - we Flashu tworzony jest string i do funkcji przekazywany jest wskaźnik do niego, czyli wskaźnik do zerowego elementu, w tym wypadku do litery 'A'=0x41=65 (nie 61)

'A' - do funkcji przekazywany jest pojedynczy char. Niezgodność typów.

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 23 wrz 2005, o 19:05

Przyszła mido głowy jeszcze coś co mogę sobie teraz z waszą pomocą wyjaśnić.
Jeżeli jest funkcja pobierająca paametry np void funkcja(char parametr) a jej wywołanie ma postać funkcja(10); To czy to jest tak jakbym tworzył sobie zmienną i w tej zamej linii ją inicjował czyli coś typu char paramet=10; czy przekazywanie do funkcji paraetru ta tak jakby dekalracja z inicjalizacja. Porawcie mnie jeśli się mylę.

a_antoniak
-
-
Posty:651
Rejestracja:13 sty 2005, o 18:38
Lokalizacja:Krasnystaw
Kontaktowanie:

Postautor: a_antoniak » 23 wrz 2005, o 20:38

To jest po prostu tak, że w ciele funkcji masz dostęp do zmiennej-parametru wywołania. Jeśli wywołujesz funkcja(10) to akurat wynosi on 10.

Z dwóch podanych ewentualności poprawniejsza jest chyba pierwsza. To jest tak jakbyś miał srodku zmienną lokalną zainicjalizowaną na 10. Ale lepiej nie myśleć tak o tym.

Co do "deklaracji z inicjalizacją". Masz na myśli coś takiego?:
void funkcja(char parametr=10);

Takie coś występuje w C++ i jest to argument domniemany. Oznacza to, że możesz wywołać funkcję bez argumentu domniemanyego, czyli w tym przypadku tak:

funkcja();

wtedy w jej wnętrzu będziesz miał parametr=10. jeśli jednak wywołasz ją tak:

funkcja(15);

to parametr będzie równy 15.

Wróć do „PLD/FPGA i inne zagadnienia techniki cyfrowej”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 52 gości