Maja znajomość tego C-iekawego języka jest raczej pobieżna i czasem trudno mi zinterpretować składnię wyszukanych zapisów kodu. Czasem wydaje mi się że to taka maniera programistów:
"im bardziej zawiła konstrukcja kodu tym podziw czytających będzie większy".
Może koledzy z większym doświadczeniem pomogą odkryć:
"Co autor kodu miał na myśli ?"
Przykład_1 Odwracanie kolejności znaków w tablicy. Pytanie dotyczy kodu instrukcji FOR po incrementacji i++.
Kod:
* odwrócenie stringów
* s = string
void reverse(int8_t s[])
{
int i, j;
char c;
for (i = 0, j = strlen(s)-1; i<j; i++,="" j--)="" {<br=""> c = s[i];
s[i] = s[j];
s[j] = c;
}
}
Podpytałem się Kolegi i twierdzi, że mogło to być związane z jakimś kodowaniem specjalnym znaków i dlatego jest to tak dziwnie. Na szybko to bardziej typowo tak:
* s = string
void reverse(int8_t s[])
{
int i, j;
char c;
for (i = 0, j = strlen(s)-1; i<j; i++,="" j--)
{
c = s[i]; //do zmiennej tymczasowej podstaw znak z pozycji i (na poczku jest ona równa zero
s[i] = s[j]; //w miejsce znaku z pozycji i podstaw znak z pozycji j(na początku ostatni znak w napisie)
s[j] = c; // w miejsce znaku z pozycji j podstaw tek skopiowany po zmiennej tymczasowej czyli ten co był pod pozycją i
}
}
a teraz przykład:
mamy napis : s = "kotołaki" -> s[0] = k, s[1] = o, itd
pokolei:
i =0, j= długość napisu -1 czyli 8 -1 = 7
c = k;
s[0] = i;
s[7] = k;
iotołakk
i++, j-- : i=1, j=6; 1 nie jest <6
c = o;
s[1] = k;
s[6] = o;
iktołaok
i++, j-- : i=2, j=5
c = t;
s[2] = a;
s[5] = t
ikaołtok
i++, j-- : i=3, j=4; 3 nie jest < 4
c = o;
s[3] = ł;
s[4] = o;
ikałotok;
i++, j-- : i = 4, j = 3; 4 jest < 3 więc mamy warunek kończący pętlę
i to by było na tyle
Rafał sorry ale nie w tym problem. Sam mechanizm odwracania kolejności jest trywialny i nie wymaga komentarza.
Tak jak napisałem problemem jest jedna linia a w zasadzie jej fragment (na czerwono).
for (i = 0, j = strlen(s)-1; i<j; i++,="" j--)="" {<br=""> c = s[i];
Specjalnie podałem link do strony na której jest kurs programowania STM32 z przykładami. To tylko prosty przykład w jakie "maliny" może nas wpędzić demo z netu.
Tu poprawna wersja kodu funkcji revers z
GitHUB
I tu wszystko jest jasne jak słońce na niebie.
Kod:
/* reverse: reverse string s in place */
static void reverse(unsigned char s[])
{
int i, j;
unsigned char c;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
A nie są to znaczniki do formatowania tekstu w edytorze?. Przekopiował przy pomocy schowka pomiędzy różnymi edytorami, nie zauważył i zostało ...
Mi to tez wyglada bardziej na rozjechany kod strony niz cudaczny zapis kodu w C.
Znacznik BR jest dosc charakterystyczny
Problem z pierwszym przykładem jest wyjaśniony i zamknięty.
W kodzie pojawiły się przypadkowe znaki, tylko czemu autor kursu tego nie poprawił ?
Przykład_2. Definicja zmiennych pod STM32
Czemu jedne zmienne są deklarowane z __IO a inne bez, jaka jest różnica ?
Kod:
__IO uint16_t CCR1_Val = 54618;
__IO uint16_t CCR2_Val = 27309;
__IO uint16_t CCR3_Val = 13654;
__IO uint16_t CCR4_Val = 6826;
uint16_t PrescalerValue = 0;
Wydawało mi się, że:
__I lotne const // definiuje "tylko do odczytu"
__O lotne // definiuje "tylko do zapisu"
__IO lotne // definiuje do "Odczyt / Zapis"
OK, rozumiem typ __I jako const np. w kodzie programu, tylko do odczytu.
Czy GCC ma typ __O, nie wydaje mi się ?
Czym różni się zwykła zmienna od takiej typu __IO ?
Jakieś wskazówki, literatura do poczytania dla zaczynających zabawę w STM32 ?
To zależy od kompilatora (czy jest natywny dla danego procesora czy nie). Typy zmiennych można sobie "definiować" samemu w pewnym sensie, czyli zakładać nazwy alternatywne dla podstawowych typów zmiennych , ale też nieco bardziej skomplikowane konstrukcje. Czasem ma to za zadanie po prostu uwidocznienie danej definicji zmiennej że jest do jakiegoś konkretnego celu, a czasem potrafi to uprościć życie. Instrukcja w C/C++ do tego to "typedef".
Przykład prosty to:
Kod:
typedef int points ;
Zdefiniowaliśmy alias dla zmiennej int, który się nazywa "points". Potem można robić:
To takie zastosowanie estetyczne.
Ale można też robić bardziej trudne aliasy, do wskaźników, struktur itp.
Trzeba by poszukać w bibliotekach które Twój kod załącza (jawnie, albo nie jawnie) bo gdzieś w nich jest prawdopodobnie napisane
Kod:
typedef long long _IO
albo coś nieco bardziej skomplikowanego
Natomiast jeśli to jest natywny kompilator, to można tego nie znaleźć, i ten typ zmiennej może być bardziej "sprytny", na przykład mieć gdzieś ograniczenie że jest np "read only" czy coś w tym stylu.
Edit: Znalazłem (chyba to to):
biblioteka core_cm3.h
Tam stoi coś takiego:
Kod:
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions */
#else
#define __I volatile const /*!< Defines 'read only' permissions */
#endif
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
/*@} end of group Cortex_M3 */
(22-04-2015 11:42)SQ5KVS napisał(a): [ -> ]
Kod:
typedef int points ;
Zdefiniowaliśmy alias dla zmiennej int, który się nazywa "points". Potem można robić:
To takie zastosowanie estetyczne.
Karolu, możliwość definiowania nowych typów w języku C nie wymyślono tylko w celach estetycznych. Mechanizm ten pozwala tworzyć rozbudowane struktury danych, nadawać im wygodne nazwy, przekazywać je jako parametry, zapisywać do pliku, odczytywać i przetwarzać w programie.
(22-04-2015 11:42)SQ5KVS napisał(a): [ -> ]
Kod:
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions */
#else
#define __I volatile const /*!< Defines 'read only' permissions */
#endif
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
/*@} end of group Cortex_M3 */
Trochę to dziwne ale wychodzi na to, że w Cortex-ach __IO i volatile to samo.
Dla mnie czym innym jest zmienna do zapisu i odczytu a czym innym zmienna typu volatile. Zwykła zmienna najczęściej jest do zapisu i odczytu a nie musi być typu volatile.
Wolę klasyczny zapis:
Kod:
uint32_t zmienna1 //zwykła zmienna odczyt/zapis
volatile uint32_t zmienna2 //zmienna odczyt/zapis ale typu volatile
(23-04-2015 21:57)SP5FCS napisał(a): [ -> ] (22-04-2015 11:42)SQ5KVS napisał(a): [ -> ](...)
To takie zastosowanie estetyczne.
Karolu, możliwość definiowania nowych typów w języku C nie wymyślono tylko w celach estetycznych. Mechanizm ten pozwala tworzyć rozbudowane struktury danych, nadawać im wygodne nazwy, przekazywać je jako parametry, zapisywać do pliku, odczytywać i przetwarzać w programie.
Często (zwłaszcza w prostych programach) typedef'u używa sie właśnie w celach "estetycznych" przez co rozumiem nadawanie nowych nazw starym typom wbudowanym, po to aby były bardziej, jakby to powiedzieć, konkretne dla kodującego .
Prosty przykład z winavr gdzie uint8t to po prostu unsigned char.
Nie napisałem jednak ze jest to wyłącznie estetyka , robienie nowych typów wskaznikowych znakomicie łagodzi ból głowy związany ze stosowaniem wskaźników albo wskaźników do funkcji, a juz w C++ niektóre konstrukcje z użyciem szablonów bez typedef powodowały by masowe samobójstwa