Goto page 1, 2 Next
Atlantis
Guest
Fri Aug 26, 2022 3:43 pm
Mam pytanie do osób w większym stopniu niż ja ogarniających zachowanie
kompilatorów języka C. Właściwie chcę się upewnić, że moje rozumowanie
jest słuszne.
Pisze obecnie pewną bibliotekę, której głównym elementem będzie maszyna
stanów. Jednym z jej głównych zadań będzie przetwarzanie i przesyłanie
dalej wiadomości wrzucanych do bufora pierścieniowego.
Od strony użytkownika będzie to wyglądało w ten sposób, że w dowolnym
momencie w programie będzie musiał wywołać funkcję, która będzie
wyglądała mniej więcej tak:
send(const char* str);
Wskaźnik str zostanie zapisany w buforze cykliczny, gdzie będzie czekał
do momentu, aż maszyna stanów będzie gotowa go odczytać i przesłać
dalej. W przypadku danych zapisywanych w RAM-ie siłą rzeczy trzeba
będzie więc zadbać, żeby żyły odpowiednio długo i np. nie znikły ze
stosu. Konieczne będzie więc używanie tablic globalnych albo lokalnych
statycznych.
A co w sytuacji, kiedy będę chciał wysłać po prostu wartość podaną
wprost w argumencie funkcji, np.?
send("przykladowy tekst");
Co w takiej sytuacji zrobi kompilator?
1. Zapisze tekst bezpośrednio we flashu i przekaże funkcji wskaźnik na
początek łańcucha zapisanego w pamięci nieulotnej.
2. Przed wywołaniem skopiuje wartość z flasha na stos i przekaże
wskaźnik do miejsca w pamięci RAM - po zwinięciu się stosu zawartość
może zostać nadpisana.
3. Zachowanie nie jest jasno zdefiniowane i zależy od innych czynników.
Oczywiście mówimy o w miarę współczesnym, 32bitowym mikrokontrolerze, z
jedną przestrzenią adresową dla flasha/RAM-u.
Najbardziej logiczna wydaje mi się opcja pierwsza, ale jak mówię - wolę
się upewnić.
Dawid Rutkowski
Guest
Fri Aug 26, 2022 4:40 pm
piątek, 26 sierpnia 2022 o 15:43:15 UTC+2 Atlantis napisał(a):
Quote:
Mam pytanie do osób w większym stopniu niż ja ogarniających zachowanie
kompilatorów języka C. Właściwie chcę się upewnić, że moje rozumowanie
jest słuszne.
Pisze obecnie pewną bibliotekę, której głównym elementem będzie maszyna
stanów. Jednym z jej głównych zadań będzie przetwarzanie i przesyłanie
dalej wiadomości wrzucanych do bufora pierścieniowego.
Od strony użytkownika będzie to wyglądało w ten sposób, że w dowolnym
momencie w programie będzie musiał wywołać funkcję, która będzie
wyglądała mniej więcej tak:
send(const char* str);
Wskaźnik str zostanie zapisany w buforze cykliczny, gdzie będzie czekał
do momentu, aż maszyna stanów będzie gotowa go odczytać i przesłać
dalej. W przypadku danych zapisywanych w RAM-ie siłą rzeczy trzeba
będzie więc zadbać, żeby żyły odpowiednio długo i np. nie znikły ze
stosu. Konieczne będzie więc używanie tablic globalnych albo lokalnych
statycznych.
A co w sytuacji, kiedy będę chciał wysłać po prostu wartość podaną
wprost w argumencie funkcji, np.?
send("przykladowy tekst");
Co w takiej sytuacji zrobi kompilator?
1. Zapisze tekst bezpośrednio we flashu i przekaże funkcji wskaźnik na
początek łańcucha zapisanego w pamięci nieulotnej.
2. Przed wywołaniem skopiuje wartość z flasha na stos i przekaże
wskaźnik do miejsca w pamięci RAM - po zwinięciu się stosu zawartość
może zostać nadpisana.
3. Zachowanie nie jest jasno zdefiniowane i zależy od innych czynników.
Oczywiście mówimy o w miarę współczesnym, 32bitowym mikrokontrolerze, z
jedną przestrzenią adresową dla flasha/RAM-u.
Najbardziej logiczna wydaje mi się opcja pierwsza, ale jak mówię - wolę
się upewnić.
Zawartość będzie zapisana we flashu, a sama zmienna (tablica znaków) w RAMie.
Podczas initu nastąpi kopiowanie z flashu do RAMu.
send("przykładowy tekst"); zaś dostanie za argument stałą - adres w RAMie.
Najprawdopodobniej każde wywołanie send("ten sam tekst"); zajmie taką
samą porcję flasha i RAMu - ale tu pewności już nie ma....
W AVR - i pewnie w innych harvardach - jest możliwość zrobienia tak,
że nie będzie używany RAM - send(PSTR("tekscik z ROMu"));
a jako argument leci wskaźnik - ale do flasha.
Ale wtedy w buforze musi być zapisana również informacja, że ten
akurat wskaźnik jest do flasha.
Myślę, że ogólnie bardzo utrudniasz sobie życie.
Atlantis
Guest
Fri Aug 26, 2022 8:25 pm
On 26.08.2022 16:40, Dawid Rutkowski wrote:
Quote:
W AVR - i pewnie w innych harvardach - jest możliwość zrobienia tak,
że nie będzie używany RAM - send(PSTR("tekscik z ROMu"));
a jako argument leci wskaźnik - ale do flasha.
Tak to było robione na części ośmiobitowych mikrokontrolerów, takich jak
PIC16/PIC18 albo właśnie AVR (i w związku z tym również większość płytek
Arduino). Żeby uniknąć kopiowania do RAM-u, trzeba było deklarować
łańcuchy tekstowe za pomocą specjalnych makrodefinicji. Istniały też
specjalne wersje funkcji do operacji na łańcuch, przygotowane z myślą o
nich.
W przypadku nowoczesnych układów 32bitowych (STM32, PIC32,
ESP8266/ESP36) nie ma już takiej potrzeby, bo zarówno flash jak i RAM
stanowią część tej samej przestrzeni adresowej i można się do nich
odwoływać za pomocą tych samych wskaźników, a łańcuchy zdefiniowane jako
const char* trafiają do flasha.
Oczywiście trzeba uważać na to co się robi, bo np. próba zapisu pod
adres we flashu spowoduje rzucenie wyjątku.
Moje pytanie dotyczyło czegoś innego - chciałem się upewnić, czy
faktycznie łańcuch zdeklarowany jako argument funkcji (a nie jawnie,
jako globalna stała z kwalifikatorem const) zawsze będzie zapisany we
flashu. Wyobraźmy sobie np. hipotetyczną sytuację:
Send("Lights on");
Send("Lightf off");
Czy nie istnieje np. ryzyko, że kompilator spróbuje to niejawnie
zoptymalizować i zdefiniuje sobie we flashy łańcuchu "Lights ", "on"
oraz "off", a potem będzie tworzył ich kombinacje na stosie, przed
przekazaniem w argumencie funkcji?
Janusz
Guest
Fri Aug 26, 2022 9:50 pm
W dniu 2022-08-26 o 20:25, Atlantis pisze:
Quote:
Moje pytanie dotyczyło czegoś innego - chciałem się upewnić, czy
faktycznie łańcuch zdeklarowany jako argument funkcji (a nie jawnie,
jako globalna stała z kwalifikatorem const) zawsze będzie zapisany we
flashu. Wyobraźmy sobie np. hipotetyczną sytuację:
Send("Lights on");
Send("Lightf off");
Czy nie istnieje np. ryzyko, że kompilator spróbuje to niejawnie
zoptymalizować i zdefiniuje sobie we flashy łańcuchu "Lights ", "on"
oraz "off", a potem będzie tworzył ich kombinacje na stosie, przed
przekazaniem w argumencie funkcji?
No to skompiluj taki program i podejrzyj co wyprodukował kompilator, ja
tak zawsze robię jak nie jestem pewien działania wyrażenia czy funkcji w
avr-ach, plik lss. (32-bitowcami się nie zajmuję).
--
Janusz
Dawid Rutkowski
Guest
Fri Aug 26, 2022 10:19 pm
piątek, 26 sierpnia 2022 o 20:26:00 UTC+2 Atlantis napisał(a):
Quote:
On 26.08.2022 16:40, Dawid Rutkowski wrote:
W AVR - i pewnie w innych harvardach - jest możliwość zrobienia tak,
że nie będzie używany RAM - send(PSTR("tekscik z ROMu"));
a jako argument leci wskaźnik - ale do flasha.
Tak to było robione na części ośmiobitowych mikrokontrolerów, takich jak
PIC16/PIC18 albo właśnie AVR (i w związku z tym również większość płytek
Arduino). Żeby uniknąć kopiowania do RAM-u, trzeba było deklarować
łańcuchy tekstowe za pomocą specjalnych makrodefinicji. Istniały też
specjalne wersje funkcji do operacji na łańcuch, przygotowane z myślą o
nich.
W przypadku nowoczesnych układów 32bitowych (STM32, PIC32,
ESP8266/ESP36) nie ma już takiej potrzeby, bo zarówno flash jak i RAM
stanowią część tej samej przestrzeni adresowej i można się do nich
odwoływać za pomocą tych samych wskaźników, a łańcuchy zdefiniowane jako
const char* trafiają do flasha.
Oczywiście trzeba uważać na to co się robi, bo np. próba zapisu pod
adres we flashu spowoduje rzucenie wyjątku.
Moje pytanie dotyczyło czegoś innego - chciałem się upewnić, czy
faktycznie łańcuch zdeklarowany jako argument funkcji (a nie jawnie,
jako globalna stała z kwalifikatorem const) zawsze będzie zapisany we
flashu. Wyobraźmy sobie np. hipotetyczną sytuację:
Send("Lights on");
Send("Lightf off");
Czy nie istnieje np. ryzyko, że kompilator spróbuje to niejawnie
zoptymalizować i zdefiniuje sobie we flashy łańcuchu "Lights ", "on"
oraz "off", a potem będzie tworzył ich kombinacje na stosie, przed
przekazaniem w argumencie funkcji?
Ale wymyśliłeś...
Ogólnie należy przypomnieć sobie C - i niezależnie, co zrobi kompilator, taka zmienna będąca argumentem funkcji ma gwarantowany czas życia tylko do wyjścia z tego konkretnego wywołania tej funkcji (a jeszcze może chciałbyś "reentrant"?).
Tak jest w C i tyle.
Więc albo sobie w tej funkcji gdzieś kopiujesz ten string albo jako argumentów używasz globali.
Grzegorz Niemirowski
Guest
Fri Aug 26, 2022 10:34 pm
Atlantis <marekw1986NOSPAM@wp.pl> napisał(a):
Quote:
Moje pytanie dotyczyło czegoś innego - chciałem się upewnić, czy
faktycznie łańcuch zdeklarowany jako argument funkcji (a nie jawnie, jako
globalna stała z kwalifikatorem const) zawsze będzie zapisany we flashu.
Wyobraźmy sobie np. hipotetyczną sytuację:
Send("Lights on");
Send("Lightf off");
Czy nie istnieje np. ryzyko, że kompilator spróbuje to niejawnie
zoptymalizować i zdefiniuje sobie we flashy łańcuchu "Lights ", "on" oraz
"off", a potem będzie tworzył ich kombinacje na stosie, przed przekazaniem
w argumencie funkcji?
Dlaczego miałby tak robić? Skąd taki pomysł? Poza tym możesz sam sprawdzić,
zajęłoby Ci to mniej czasu niż pisanie posta. Nie mówiąc o czekaniu na
odpowiedzi.
..
Potwierdzam, że GCC na cortex-m4 umieszcza łańcuch we Flashu i przekazuje do
niego wskaźnik.
--
Grzegorz Niemirowski
https://www.grzegorz.net/
JDX
Guest
Sat Aug 27, 2022 6:27 am
J.F
Guest
Sat Aug 27, 2022 6:41 am
On Fri, 26 Aug 2022 20:25:57 +0200, Atlantis wrote:
Quote:
Moje pytanie dotyczyło czegoś innego - chciałem się upewnić, czy
faktycznie łańcuch zdeklarowany jako argument funkcji (a nie jawnie,
jako globalna stała z kwalifikatorem const) zawsze będzie zapisany we
flashu. Wyobraźmy sobie np. hipotetyczną sytuację:
Send("Lights on");
Send("Lightf off");
Czy nie istnieje np. ryzyko, że kompilator spróbuje to niejawnie
zoptymalizować i zdefiniuje sobie we flashy łańcuchu "Lights ", "on"
oraz "off", a potem będzie tworzył ich kombinacje na stosie, przed
przekazaniem w argumencie funkcji?
Zbyt przekombinowane, C takie nie jest
Szczegolnie, ze ma przekazac adres tekstu.
Ale .. jak juz mowa o "lepszych prockach" ... generujesz do niego
wlasny program, czy masz tam jakis "boot loader", ktory ten Twoj
program w jakis sposob startuje?
Przepisywanie programu z flash do RAM tez bylo modne, bo flash za
wolny ...
J.
Atlantis
Guest
Sat Aug 27, 2022 8:10 am
On 26.08.2022 22:19, Dawid Rutkowski wrote:
Quote:
Ale wymyśliłeś... Ogólnie należy przypomnieć sobie C - i niezależnie,
co zrobi kompilator, taka zmienna będąca argumentem funkcji ma
gwarantowany czas życia tylko do wyjścia z tego konkretnego wywołania
tej funkcji (a jeszcze może chciałbyś "reentrant"?). Tak jest w C i
tyle.
Jeśli już proponujesz przypomnienie sobie C, to należałoby sobie
przypomnieć czym jest const char* (albo char*) w tym języku. Tutaj nie
mamy do czynienia z czymś takim jak String C++ albo innych językach
wysokiego poziomu. To nie jest obiekt albo kontener na dane, podczas
tworzenia którego zachodziłaby alokacja pamięci.
To jest po prostu zwykły wskaźnik, który przechowuje jedną, jedyną
informację - adres początku łańcucha znaków w pamięci.
Żeby pokazać różnicę, wyobraźmy sobie następną sytuację w C:
const char* globalny_wskaznik = NULL;
void foo(const char* str) {
globalny_wskaznik=str;
}
Z następującą sytuacją w C++:
std::String globalny_string;
void bar(std::String str) {
globalny_string = str;
}
Co się stanie po wywołaniu pierwszej funkcji? Otrzyma ona wskaźnik z
adresem na jakiś obszar w pamięci. Adres ten zostanie przekopiowany do
globalnego wskaźnika, a sam str zostanie zdjęty ze stosu. To co się
będzie działo z samymi danymi na które wskazywał nie jest w żaden sposób
określone - wszystko zależy od tego o jakim typie pamięci mówimy. Mogą
rezydować wiecznie we flashu, mogą być cały czas dostępne jako zmienna
globalna w RAM-ie, ale mogą też zniknąć w wyniku zdjęcia ze stosu albo
dealokacji ze sterty w innej części programu.
Co się natomiast dzieje w drugim przykłaadzie? Wywołanie funkcji
powoduje utworzenie obiektu klasy std::String, który zostaje
zainicjowany konkretnym tekstem i utworzy swoją instancję w pamięci. W
skutek użycia operacji przypisania zostanie wywołany konstruktor
kopiujący, który utworzy osobną kopię zawartości str w obiekcie
globalny_string. Po wyjściu z funkcji bar zostanie wywołany destruktor
obiektu str, jednak jego globalna kopia będzie nadal istniała.
Dawid Rutkowski
Guest
Sat Aug 27, 2022 10:28 am
sobota, 27 sierpnia 2022 o 08:11:18 UTC+2 Atlantis napisał(a):
Quote:
On 26.08.2022 22:19, Dawid Rutkowski wrote:
Ale wymyśliłeś... Ogólnie należy przypomnieć sobie C - i niezależnie,
co zrobi kompilator, taka zmienna będąca argumentem funkcji ma
gwarantowany czas życia tylko do wyjścia z tego konkretnego wywołania
tej funkcji (a jeszcze może chciałbyś "reentrant"?). Tak jest w C i
tyle.
Jeśli już proponujesz przypomnienie sobie C, to należałoby sobie
przypomnieć czym jest const char* (albo char*) w tym języku. Tutaj nie
mamy do czynienia z czymś takim jak String C++ albo innych językach
wysokiego poziomu. To nie jest obiekt albo kontener na dane, podczas
tworzenia którego zachodziłaby alokacja pamięci.
To jest po prostu zwykły wskaźnik, który przechowuje jedną, jedyną
informację - adres początku łańcucha znaków w pamięci.
Żeby pokazać różnicę, wyobraźmy sobie następną sytuację w C:
const char* globalny_wskaznik = NULL;
void foo(const char* str) {
globalny_wskaznik=str;
}
Z następującą sytuacją w C++:
std::String globalny_string;
void bar(std::String str) {
globalny_string = str;
}
Co się stanie po wywołaniu pierwszej funkcji? Otrzyma ona wskaźnik z
adresem na jakiś obszar w pamięci. Adres ten zostanie przekopiowany do
globalnego wskaźnika, a sam str zostanie zdjęty ze stosu. To co się
będzie działo z samymi danymi na które wskazywał nie jest w żaden sposób
określone - wszystko zależy od tego o jakim typie pamięci mówimy. Mogą
rezydować wiecznie we flashu, mogą być cały czas dostępne jako zmienna
globalna w RAM-ie, ale mogą też zniknąć w wyniku zdjęcia ze stosu albo
dealokacji ze sterty w innej części programu.
Co się natomiast dzieje w drugim przykłaadzie? Wywołanie funkcji
powoduje utworzenie obiektu klasy std::String, który zostaje
zainicjowany konkretnym tekstem i utworzy swoją instancję w pamięci. W
skutek użycia operacji przypisania zostanie wywołany konstruktor
kopiujący, który utworzy osobną kopię zawartości str w obiekcie
globalny_string. Po wyjściu z funkcji bar zostanie wywołany destruktor
obiektu str, jednak jego globalna kopia będzie nadal istniała.
Tutaj już czas na przypomnienie sobie "Alicji w krainie czarów" - rozdziału z piosenką bodajże Białego Rycerza (czyli skoczka):
"Nazwa tej piosenki nazywa się >>rybie oczy<<" itd.
Czyli różnica między nazwą wskaźnika, zawartością wskaźnika, nazwą tablicy i zawartością tablicy.
Przy wywołaniu send("tekscik"), gdy send(const char *aArg),
"tworzony" jest zarówno wskaźnik aArg jak i anonimowa tablica z zawartością "tekscik".
I obie te zmienne mają czas życia do zakończenia wywołania tej funkcji.
Jakaś sekta twierdzii, że "dynamicznie" można tworzyć tylko obiekty?
Różnica jest tylko taka, że przy tworzeniu obiektu wywoływany jest konstruktor (w C++ cholera wie, który).
A co do send(const char *aArg)
to nigdy nie potrafiłem zapamiętać, czy zabronione jest zmienianie
wartośvi aArg czy też wartości wskazywanej...
Czyli czy nie wolno:
aArg=b;
czy
aArg[3]=c;
Bo była chyba jeszcze konstrukcja, która nie pozwalała na to inne podstawienie.
Ogólnie to są bzdury do męczenia studentów.
C K&R rulez na wieki ;>
Marek
Guest
Sat Aug 27, 2022 11:34 am
On Fri, 26 Aug 2022 20:25:57 +0200, Atlantis <marekw1986NOSPAM@wp.pl>
wrote:
Quote:
Send("Lights on");
Send("Lightf off");
Tak z ciekawości pytam, czemu opisy stanów jako parametry robocze
mają być stringami? To ma działać na styku z białkiem?
--
Marek
JDX
Guest
Sat Aug 27, 2022 11:53 am
On 27.08.2022 10:28, Dawid Rutkowski wrote:
[...]
Quote:
A co do send(const char *aArg)
to nigdy nie potrafiłem zapamiętać, czy zabronione jest zmienianie
wartośvi aArg czy też wartości wskazywanej...
Czyli czy nie wolno:
aArg=b;
Wolno.
Quote:
czy
aArg[3]=c;
Nie wolno.
Quote:
Bo była chyba jeszcze konstrukcja, która nie pozwalała na to inne podstawienie.
Nadal jest: send(const char * const aArg)
Quote:
Ogólnie to są bzdury do męczenia studentów.
C K&R rulez na wieki ;
Zwłaszcza trigraphy.

Atlantis
Guest
Sat Aug 27, 2022 12:59 pm
On 27.08.2022 10:28, Dawid Rutkowski wrote:
Quote:
Przy wywołaniu send("tekscik"), gdy send(const char *aArg),
"tworzony" jest zarówno wskaźnik aArg jak i anonimowa tablica z zawartością "tekscik".
I obie te zmienne mają czas życia do zakończenia wywołania tej funkcji.
Tutaj nie masz racji, a przynajmniej opisywane przez Ciebie zachowanie
nie jest żadną uniwersalną regułą. Nie ma żadnej zasady która mówiłaby,
że anonimowa tablica jest tworzona na stosie tuż przed utworzeniem
wskaźnika, który by na nią wskazywał.
Takie ciągi znaków zwykle są zbierane podczas kompilacji i umieszczone w
rodata (czyli w przypadku mikrokontrolerów najczęściej we flashu) i
potem po prostu wskaźnik będzie inicjowany wartością wskazującą na
początek odpowiedniego ciągu znaków.
Widać to chociażby w HEX-ach wsadów do starszych systemów
mikroprocesorowych (Z80, 8051) gdzie wszystkie teksty są zebrane w
jednym miejscu.
Problemy pojawiają się w przypadku niektórych architektur, gdzie
kompilator (o ile nie poinformujemy go, by robił inaczej) będzie przy
starcie programu kopiował dane do RAM-u, bo wskaźnik na dane w RAM-ie i
we flashu to nie to samo. Nawet wtedy ciągle jednak będą one istniały
cały czas w formie zmiennych globalnych, a nie zostanę ulokowane na stosie.
Moje pytanie odnosiło się do czegoś innego - chciałem się upewnić, czy
przypadkiem w pewnych sytuacjach program w sposób niejawny nie zrobi mi
niespodzianki i np. zamiast użyć wskaźnika wprost do ciągu w rodata w
sposób niejawny nie wygeneruje tymczasowego tekstu na stosie, złożonego
z fragmentów innych tekstów, w ramach optymalizacji.
Quote:
A co do send(const char *aArg)
to nigdy nie potrafiłem zapamiętać, czy zabronione jest zmienianie
wartośvi aArg czy też wartości wskazywanej...
w przypadku const char* masz do czynienia ze wskaźnikiem na const char.
Czyli nie wolno ci modyfikować wartości na którą wskazuje wskaźnik, ale
już sam wskaźnik możesz modyfikować. Zabronione jest *aArg='a', ale już
jak najbardziej wykonasz aArg++. Bez tego nie byłoby przecież możliwe
iterowanie po łańcuchach tekstowych w formie const char*.
W C istnieją też wskaźniki char* const - w tym przypadku możesz
modyfikować zawartość, ale już nie wolno zmienić adresu na który
wskazuje wskaźnik.
Dostępna jest też najbardziej restrykcyjna kombinacja: const char* const
- ani nie zmodyfikujesz wartości, ani adresu na który wskazuje wskaźnik.
Dawid Rutkowski
Guest
Sat Aug 27, 2022 3:59 pm
sobota, 27 sierpnia 2022 o 12:59:44 UTC+2 Atlantis napisał(a):
Quote:
On 27.08.2022 10:28, Dawid Rutkowski wrote:
Przy wywołaniu send("tekscik"), gdy send(const char *aArg),
"tworzony" jest zarówno wskaźnik aArg jak i anonimowa tablica z zawartością "tekscik".
I obie te zmienne mają czas życia do zakończenia wywołania tej funkcji.
Tutaj nie masz racji, a przynajmniej opisywane przez Ciebie zachowanie
nie jest żadną uniwersalną regułą. Nie ma żadnej zasady która mówiłaby,
że anonimowa tablica jest tworzona na stosie tuż przed utworzeniem
wskaźnika, który by na nią wskazywał.
Takie ciągi znaków zwykle są zbierane podczas kompilacji i umieszczone w
rodata (czyli w przypadku mikrokontrolerów najczęściej we flashu) i
potem po prostu wskaźnik będzie inicjowany wartością wskazującą na
początek odpowiedniego ciągu znaków.
Widać to chociażby w HEX-ach wsadów do starszych systemów
mikroprocesorowych (Z80, 8051) gdzie wszystkie teksty są zebrane w
jednym miejscu.
Problemy pojawiają się w przypadku niektórych architektur, gdzie
kompilator (o ile nie poinformujemy go, by robił inaczej) będzie przy
starcie programu kopiował dane do RAM-u, bo wskaźnik na dane w RAM-ie i
we flashu to nie to samo. Nawet wtedy ciągle jednak będą one istniały
cały czas w formie zmiennych globalnych, a nie zostanę ulokowane na stosie.
Moje pytanie odnosiło się do czegoś innego - chciałem się upewnić, czy
przypadkiem w pewnych sytuacjach program w sposób niejawny nie zrobi mi
niespodzianki i np. zamiast użyć wskaźnika wprost do ciągu w rodata w
sposób niejawny nie wygeneruje tymczasowego tekstu na stosie, złożonego
z fragmentów innych tekstów, w ramach optymalizacji.
Piszesz w C.
Nie w asemblerze, który z tego C zrobi kompilator.
Zrobi jak zrobi i może nawet działać.
Ale nie ma pewności.
Inny kompilator, a nawet ten sam z innym -Ox, może zrobić inaczej i działać już nie będzie.
Jak jest send("tekscik") to po zakończeniu tej funkcji "tekscik" w tym samym miejscu w pamięci może dalej być, ale nie musi.
Dlatego należy go skopiować - albo dawać wskaźnik na globala.
Tyle z punktu widzenia C.
Wskaźniki nie są do zabawy - bardzo łatwo utrudnić sobie życie.
Cóż, nikt do C nie zmusza - można pusać w assemblerze, możnasobie zmodyfikować język i kompilator - tylko wtedy już nie będzie to C.
Dawid Rutkowski
Guest
Sat Aug 27, 2022 4:06 pm
sobota, 27 sierpnia 2022 o 11:53:58 UTC+2 JDX napisał(a):
Quote:
Ogólnie to są bzdury do męczenia studentów.
C K&R rulez na wieki ;
Zwłaszcza trigraphy.
O, czego to się człowiek nie dowie na starość...
Ale czy to na pewno K&R C?
Nie pamiętam tego z książki (a książka na poziomie "Diuny"

,
no i nie jest to coś, co jest potrzebne samo z siebie, a dopiero
na komputerach w dzikich krajach, co nie mają ASCII, a jakiś np. ISO646 (no dobra EDBIC też miał kłopot, ale na IBM360 pusze się w FORTRANie ;)
Ale jest fajne.
Poubarwiam tak niektóre programy ;>
Goto page 1, 2 Next