Skocz do zawartości

Forced typecasting - gdzie sens i logika ?


Pomocna odpowiedź

Czy ktoś ze speców od C może mi objaśnić ten bałagan i niekonsekwencję?

void adc_INJ_configure(uint8_t channel)

ADC1->JSQR &= ~(0x1FUL << 15);
ADC1->JSQR |= (channel << 15);

...

W pierwszym przypadku 0x1F jest wymuszane jako Unsigned Long czyli 0x0000001F. W drugim przypadku zmienna channel jest typu uint8_t i nie jest rzutowania do UL. Skoro wszystko i tak działa to po jaki gwint są te zabawy w dopiski UL, jeżeli nie ma w tym konsekwencji?

Co więcej  w definicjach z plików nagłówkowych bardzo często stosowana jest formuła:

#define BIT15 (1UL << 15UL)

Czyli jak by nie dało się jedynki przesunąć w lewo 15 razy, jeżeli ta "piętnastka" nie jest uint32_t? Owszem rozumiem, że jeżeli jedynka byłaby uint8_t, to faktycznie 15 razy nie dałoby się jej przesunąć, natomiast typecasting tej 15 jest bez sensu (?)

Jaki sens mają te dziwactwa? Bo przyznam szczerze, że to wszystko nie dość że nie pomaga, to tylko wprowadza ogromne zamieszanie i , błędną interpretację pojmowania tego "kodu".

Domyślam się że ma to powiązanie z automatyczną promocją wielkości (szerokości bitowej) typu zmiennej dla danej platformy sprzętowej... Ale zaprezentowane przykłady naprawdę nie pomagają w nauce, czy zrozumieniu C.

Link to post
Share on other sites
(edytowany)

Strzelając, że ten kod to STM32, gdzie int ma niewątpliwie 32 bity, to nie wydaje mi się, żeby w którymkolwiek z powyższych przykładów użycie UL było niezbędne. Może po prostu autor lubi być bardziej explicit niż implicit. A podobno o gustach się nie dyskutuje. Ten #define na końcu jest jeszcze większą przesadą, bo siłą rzeczy, jak ta lewa strona będzie unsigned long, to prawa też. Chyba że ktoś pracował kiedyś z jakimś egzotycznym kompilatorem w wersji alfa, który wszystko kompilował dokładnie tak jak jest napisane i nawet nie umiał policzyć stałego wyrażenia podczas kompilacji.

Edytowano przez trainee
  • Lubię! 1
Link to post
Share on other sites
(edytowany)

Nie wiem z czego te cytaty były, no ale ze stylami kodowania bywa różnie, niekoniecznie zawsze dobrze.

Edytowano przez trainee
Link to post
Share on other sites
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Pierwszy cytat był z kursu programowania po rejestrach stąd:

https://www.mutex-embedded.com/courses

Od dwóch tygodni autor mi jeszcze nie odpowiedział na to pytanie.

Drugie gdzieś widziałem chyba w nagłówkach od STM, teraz nie pamiętam gdzie, ale żeby nie szukać daleko, może nie bezpośrednio ale też jest UL

 

/*******************  Bit definition for USB_ISTR register  *******************/
#define USB_ISTR_EP_ID_Pos                      (0U)                           
#define USB_ISTR_EP_ID_Msk                      (0xFUL << USB_ISTR_EP_ID_Pos)   /*!< 0x0000000F */

 

Poza tym to suffixowanie tym UL sprawia że kod jest mniej czytelny, bo zamiast np. 0x1F powstaje jakiś dziwny string 1FUL i w pierwszej chwili nie wiadomo co to jest. Byłbym za taką standaryzacją, żeby było to od razu jednoznaczne, bo to UL na różnych platformach może mieć różną długość, a 

uint32_t, int32_t, uint8_t itd.

jest takie samo na każdej platformie.

 

Link to post
Share on other sites
16 minut temu, virtualny napisał:

uint32_t, int32_t, uint8_t itd.

jest takie samo na każdej platformie.

Jak się zapisuje literał uint16_t?

 

Link to post
Share on other sites
(edytowany)

@ethanak Pojęcia nie mam, C dopiero staram się uczyć. Strzelam że "U", ale ono może być różnie promowane w zależności od platformy i jak mniemam, po to właśnie powstały typy uint32_t i tak dalej... żeby uniknąć natywnych promocji, pozostawiając kod bardziej przenośny.

 

edit:

O ile mi wiadomo to dla MSP430 będzie właśnie UL

 

Edytowano przez virtualny
Link to post
Share on other sites
(edytowany)
1 godzinę temu, virtualny napisał:

/*******************  Bit definition for USB_ISTR register  *******************/
#define USB_ISTR_EP_ID_Pos                      (0U)                           
#define USB_ISTR_EP_ID_Msk                      (0xFUL << USB_ISTR_EP_ID_Pos)   /*!< 0x0000000F */

Jakaś hipoteza, która mi przychodzi do głowy, to że to może być przyzwyczajenie, by uniknąć sytuacji, w której jakaś maska po przesuwaniu zostanie ujemnym signed int, bo operacje bitowe na takich są niezdefiniowane.

Co prawda jeżeli celuje się w platformę, gdzie unsigned long i unsigned int mają oba po 32 bity, to pytanie czemu nie po prostu 0xFU.

1 godzinę temu, virtualny napisał:

Poza tym to suffixowanie tym UL sprawia że kod jest mniej czytelny, bo zamiast np. 0x1F powstaje jakiś dziwny string 1FUL i w pierwszej chwili nie wiadomo co to jest.

Myślę, że trochę przesadzasz z denerwowaniem się tym. Kwestia przyzwyczajenia się do danego języka. Potem już wiadomo, co to jest. No i potem można się radować, że ma się w kodzie Mocny 0xFULL.

1 godzinę temu, virtualny napisał:

Byłbym za taką standaryzacją, żeby było to od razu jednoznaczne, bo to UL na różnych platformach może mieć różną długość

1 godzinę temu, ethanak napisał:

Jak się zapisuje literał uint16_t?

Tak, to jest dobra koncepcja, np.:

#include <inttypes.h>
#include <stdio.h>

uint64_t problem = 1 << 31;
uint64_t possibility = 1U << 31;

uint64_t macro = UINT64_C(1) << 31;
uint64_t cast = (uint64_t)1 << 31;

int main()
{
	printf("%" PRIx64 "\n", problem);
	printf("%" PRIx64 "\n", possibility);

	printf("%" PRIx64 "\n", macro);
	printf("%" PRIx64 "\n", cast);
}

Efekt do zaobserwowania tam, gdzie int ma 32 bity. Jeśli chodzi o makro UINT64_C z inttypes.h, to dla clang i gcc na ARM 32 jest rozwijane do sufiksu ULL. W każdym razie te makra w sposób przenośny rozwijają się do właściwej formy. Nie wiem czy jest jakiś powód, dla którego użycie rzutowania miałoby dać gorszy skutek w kompilacji niż użycie makra.

Np. wynik na x86-64, gdzie int ma 32 bity:

ffffffff80000000
80000000
80000000
80000000
80000000
Edytowano przez trainee
Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.