Jak poprawnie zwracać wartość?

0

Jak w temacie. Ciągle mi zarzucacie, że nie znam podstaw itp itd... no to rzucam pierwszy lepszy przykład z brzegu którym się zająłem - tak, zaraz powiecie, że zaczynam od d... strony, a nie od początku, możliwe, że tak ale tym przykładem chcę udowodnić, że ile by podręczników do podstaw nie przeczytał to i tak wszystkiego się w nich nie znajdzie. Może tutaj znajdzie się jakieś wyjaśnienie z przykładem

Zacznę od kodu który napisałem w wątku

Przypomnę kod

int SettingsFile::readSettings()
{
    QFile readFileJson;

    readFileJson.setFileName(QString("settings.json"));

    if(!readFileJson.open(QIODevice::ReadOnly | QIODevice::Text)){
        qInfo()<< "nie mozna odczytac pliku";

        return 2; //numer błędu
    }
    else{
        QByteArray data;
        data = readFileJson.readAll();

        return 0; //numer informujący, że coś się powiodło
    }

    return -2; //nieprzewidzany wyjątek...
}

niejaki @_13th_Dragon zarzucił mi, że źle zwracam wartość za pomocą return ok. możliwe, że robię to źle ale czytając dokumentację

  1. https://en.cppreference.com/w/cpp/language/return
  2. https://www.w3schools.com/cpp/cpp_function_return.asp
  3. https://www.programiz.com/cpp-programming/return-reference
  4. https://www.digitalocean.com/community/tutorials/return-array-in-c-plus-plus-function

natykam się, że tak to ujmę - na standardowe użycie - i to dotyczy DOSŁOWNIE KAŻDEGO PODRĘCZNIKA DO PODSTAW - nikt w tych rozważaniach nie skupia się na różnych przypadkach użycia return - co ciekawe nawet inni mają problem z poprawnym zwróceniem wartości

  1. https://stackoverflow.com/questions/1735038/why-not-all-control-paths-return-a-value-is-warning-and-not-an-error
  2. https://stackoverflow.com/questions/1734927/compare-characters-at-the-end-of-the-string-c
  3. https://stackoverflow.com/questions/67284316/non-void-function-does-not-return-a-value-in-all-control-paths-in-c

Mając na uwadze powyższe, bezzasadne są zarzuty, że nie znam podstaw - dla mnie użycie na przykład return w różnych przypadkach wynika bardziej z doświadczenia programistycznego, aniżeli z oczytania się książkami od podstaw.

Teraz czas na przykłady uwag od kompilatora

nawet rada @_13th_Dragon aby usunąć else nic nie daje (poniżej screeny z kompilatora, gdyż chcę pokazać żółte uwagi)

  1. Screen 1
    screenshot-20221221092350.png

  2. Screen 2
    screenshot-20221221092602.png

  3. Screen 3 - dlaczego poniżej nie ma uwagi ?
    screenshot-20221221092729.png

na koniec chcę dodać - TYLKO KULTURALNA merytoryczna rozmowa, BEZ bluzg, tzw. wycieczek osobistych i nic nie wnoszących krótkich zwrotów typu wróć do podstaw, doucz się, pomyśl itp. bo to nie prowadzi do niczego, niczego nie wnosi i w takich warunkach nie da się nabyć poprawnej wiedzy aby pójść do przodu, takich rozmów NIGDY nie toleruję - bo jak sam wątek wskazuje, wszystkich możliwych przypadków i pełnej wiedzy o programowaniu dowolny autor podręcznika nie opisze, a w zasadzie nie wyczerpie - dlatego potrzebna jest wymiana wiedzy i doświadczenia między nami.

1

TYLKO KULTURALNA merytoryczna rozmowa, BEZ bluzg, tzw. wycieczek osobistych

Znaczy nie będziesz się odzywał?
przykłady miałes, z optionalem, omówione enumy, pary itd. Nawet refactoring zaczęty.

Przypomnę kod

To słabo przypominasz bo tam był bool nie int.

To musi być trolling bo ten post nie ma sensu.

4

Grunt aby dopilnować aby nie istniała żadna ścieżka prowadząca do braku return
Miałeś:

int fun(int a)
{
  if(isError())
  {
     //do something when error
     return 2;
  }
  else
  {
     //do something when ok
     return 0;
  }
  return -2;
}

Moja propozycja była usunąć zbędny return -2; ponieważ nie da rady aby on kiedykolwiek się wykonał (czyli kompilator wyplunie przynajmniej hint), czyli:

int fun(int a)
{
  if(isError())
  {
     //do something when error
     return 2;
  }
  else
  {
     //do something when ok
     return 0;
  }
}

Oraz usunięcie else aby zmniejszyć złożoność kodu, czyli:

int fun(int a)
{
  if(isError())
  {
     //do something when error
     return 2;
  }
  //do something when ok
  return 0;
}

Podsumowując, brakuje ci podstaw nawet dla tego aby zrozumieć o czym mówimy.

3

Pierwsza rzecz — zadawanie zagadek nielogicznych z cyklu „jakie mam ostrzeżenie i dlaczego” bez pokazania samego ostrzeżenia jest mocno w złym tonie. Ale cóż, mam wolne, idą święta, mam dobry humor… Raz do roku można.

Gdzieś tam, w tych podstawach, z którymi się zapoznałeś, dowiedziałeś się, że funkcja która coś zwraca (czyli nie void), musi… coś zwracać¹. Czyli mieć return na każdej możliwej ścieżce wykonania. Kod ze screena pierwszego:

int fun1(int a) {
  if (a == 1) {
    return a;
  }
}

jest zatem niepoprawny, bo nie ma returna dla wszystkich ścieżek — w szczególności nie zadowala sytuacji, w której a == 42.

Idendycznie, kod ze screena drugiego:

int fun2(int a) {
  if (a == 1) {
    return a;
  } else if (a == 2) {
    return a;
  }
}

jest niepoprawny z dokładnie tego samego powodu.

Zaś wreszcie kod ze screena trzeciego jest formalnie poprawny, bo ten problem nie występuje:

int fun3(int a) {
  if (a == 1) {
    return a;
  } else {
    return a;
  }
}

Jest, co prawda, w praktyce niepoprawny, bo robi to samo na różnych ścieżkach instrukcji warunkowej, ale jest, jak pisałem, formalnie poprawny, więc linter nie narzeka.

Twój oryginalny kod, z poprzedniego wątku, miał inny problem — zawierał martwy kod. Martwy kod to taki, który się nigdy nie wykona, na żadnej ścieżce. Zauważ, że return zakańcza wykonanie funkcji zwróceniem wyniku — po to jest. Jak masz konstrukcję typu:

if (warunek()) {
  // cośtam, cośtam;
  return cokolwiek1;
else {
  // cośtam, cośtam;
  return cokolwiek2;
}
// wszystko tutaj to martwy kod

To ostatni komentarz sygnalizuje martwy kod. Coś, o czym linter Cię powinien ostrzec. W C++ akurat to nie jest błąd krytyczny (tzn. taki, który wg standardu musi powstrzymać kompilację), ale w wielu innych językach już tak — i słusznie, bo jego występowanie to zawsze błąd programisty. Oprócz tego, tak jak w przykładzie trzecim, masz jeszcze inny problem — z nadmiarowością. else jest tutaj nadmiarowe (więc niepotrzebne). Jako że wszystko objęte w tego else’a, z konieczności, albo nie wykona się wcale (bo ścieżka wykonania przeszła przez ifa), albo będzie ostatnią rzeczą, którą robi funkcja (bo kończy się returnem), to nie ma sensu tego pakować w else — przepływ sterowania będzie wyglądał dokładnie tak samo. Są lintery, które przed tym ostrzegają (clang-tidy na odpowiednio wysokich ustawieniach, na przykład).


¹ int main jest funkcją specjalną i ma domniemany return, którego nie trzeba pisać jawnie. IMO to więcej komplikuje niż upraszcza, ale cóż…

1

Tylko MSVC wykrywa bezsensowny return: https://godbolt.org/z/PMTP633Eo
gcc stracił taką możliwość z powodu niekonsekwencji między wersjami: https://stackoverflow.com/a/21240321/1387438
a clang naśladuje gcc (szczególnie tak stary jak gcc 4.4).

0
zkubinski napisał(a):

Przypomnę kod

int SettingsFile::readSettings()
{
    QFile readFileJson;

    readFileJson.setFileName(QString("settings.json"));

    if(!readFileJson.open(QIODevice::ReadOnly | QIODevice::Text)){
        qInfo()<< "nie mozna odczytac pliku";

        return 2; //numer błędu
    }
    else{
        QByteArray data;
        data = readFileJson.readAll();

        return 0; //numer informujący, że coś się powiodło
    }

    return -2; //nieprzewidzany wyjątek...
}

niejaki @_13th_Dragon zarzucił mi, że źle zwracam wartość za pomocą return ok. możliwe, że robię to źle ale czytając dokumentację

Z tego co pamiętam, to początkowo miałeś bool SettingsFile::readSettings(), i @_13th_Dragon powiedział, że jak funkcja zwraca bool, to return 0; to jest implicitly return false;, a wszystko pozostałe to jest return true; - int zostanie niejawnie zamieniony na bool.

Co do reszty Pytania, to Twój kod pasuje do kodu poglądowego

if (!condition) {
  return 2;
} else {
  return 0;
}
return -2;

Zauważ, że w tej sytuacji ten ostatni return -2 nigdy się nie wykona. Jeśli masz return zarówno if jak i else, to na pewno jeden z nich zwróci z funkcji, i żaden kod poniżej nie ma szans się uruchomić, więc można go pominąć.

Co do else, to również jest zbędny, Twój kod można zamienić na taki:

if (!condition) {
  return 2;
} 
if (condition) { // zamiast "else"
  return 0;
}
return -2;

I możesz tutaj zauważyć, że w momencie w którym wchodzimy do if (condition), to condition MUSI być prawdziwy (true) (bo gdyby nie był, to wszedłby do if (!condition) i zwrócił z funkcji), więc if tautologiczny (który zawsze jest true) i można jaknajbardziej go usunąć.

if (!condition) {
  return 2;
} 
// "else" niepotrzebny
return 0;

return -2;

Teraz dużo bardziej widać, ze funkcja najpierw zrobi return 0;, a szansy na zwrócenie -2 nigdy nie ma, można więc go usunąć:

if (!condition) {
  return 2;
} 
return 0;

I to jest kod który został Ci zaproponowany.

0

@_13th_Dragon:

Moja propozycja była usunąć zbędny return -2; ponieważ nie da rady aby on kiedykolwiek się wykonał (czyli kompilator wyplunie przynajmniej hint), czyli:

niekoniecznie, bo w przytoczonych przeze mnie linkach, ktoś pisze, że mimo wszystko return na końcu musi być, bo nie jesteś w stanie przewidzieć czy dany warunek KIEDYKOLWIEK się spełni - PONIŻEJ NAPRAWDĘ UPROSZCZONY PRZYPADEK

int fun(int a);

int main()
{
    cout << fun(3) << endl;
}

int fun(int a)
{
    if(a==1){
        return a;
    }
    else if(a==2){
        return a;
    }
    return 0; //mimo wszystko musi być, bo może być sytuacja, że ŻADEN warunek się nie spełni
}

w linkach co dałem, ktoś pisze, że kiedyś w tradycyjnym C funkcje były TYLKO void i jak ktoś chciał coś zwrócić, to musiał dać tego returna - sam pamiętam, jak kompilator przy funkcji void dopuszczał wartość zwracaną - zgodziłbym się, żeby niewłaściwie użyte return było traktowane jako błąd, a nie uwaga - ale ze względu na kompatybilność wsteczną z językiem C, kompilatory wypluwają tylko uwagę

1
zkubinski napisał(a):

@_13th_Dragon:

Moja propozycja była usunąć zbędny return -2; ponieważ nie da rady aby on kiedykolwiek się wykonał (czyli kompilator wyplunie przynajmniej hint), czyli:

niekoniecznie, bo w przytoczonych przeze mnie linkach, ktoś pisze, że mimo wszystko return na końcu musi być, bo nie jesteś w stanie przewidzieć czy dany warunek KIEDYKOLWIEK się spełni - PONIŻEJ NAPRAWDĘ UPROSZCZONY PRZYPADEK

int fun(int a);

int main()
{
    cout << fun(3) << endl;
}

int fun(int a)
{
    if(a==1){
        return a;
    }
    else if(a==2){
        return a;
    }
    return 0; //mimo wszystko musi być, bo może być sytuacja, że ŻADEN warunek się nie spełni
}

No i w tym kodzie faktycznie nie można usunąć żadnego returna, bo żaden z nich nie jest nadmiarowy.

Ale Tutaj masz if, else if. A W twoim głównym przykładzie masz tylko if, else - i w Tym Twoim return już jest.

Pozwól że znowu dam Ci dwa przykłady:

int fun(int a)
{
    if (a==1) {
        return a;
    }
    else if (a==2) {
        return a;
    }
    return 0; // return konieczny, czasem się wykona
}
int fun(int a)
{
    if (a==1) {
        return a;
    }
    else {
        return a;
    }
    return 0; // return niepotrzebny - nigdy się nie wykona
}

Dygresja

A wracając do linków, które podesłałeś, o "dobrych praktykach" że return ma być na końcu, to one się wzięły stąd, że kiedyś wczesne wersje kompilatorów w C miały taką optymalizacje, że jeśli funkcja ma jeden return na końcu funkcji, to potrafiły jakoś wsadzić to wywołanie pod użycie, i tym samym oszczędzić kilka kroków procesora w skompilowanym kodzie maszynowym. To przez pewien czas powodowało że programiści pisali pojedyncze returny na końcu funkcji, i była to nazwana "dobra praktyka".

Tylko że mało kto wie, że pare lat później (czyli gdzieś w latach 1990-1995) poprawiono to, i teraz ta optymalizacja występuje, nawet jak jest wiele returnów w wielu miejscach, ale niestety mało kto to wiedział i rozumiał i "dobra praktyka" została do dzisiaj, czasem nawet w innych, niekompilowanych językach.

2
zkubinski napisał(a):

w linkach co dałem, ktoś pisze, że kiedyś w tradycyjnym C funkcje były TYLKO void i jak ktoś chciał coś zwrócić, to musiał dać tego returna

Obstawiam że to twój brat bliźniak a przynajmniej bratnia dusza. Nie wierz wszystkiemu co tacy piszą. To jest totalna bzdura.
Kiedyś właśnie nie było void a domyślny był typ int czyli się pisało:
fun() { return 42; } - domyślnie zwraca int
albo:
add(a,b) { return a+b; } - domyślnie zwraca int, zaś a i b też domyślnie typu int
te dwie powyższe rzeczy wciąż przejdą w C, owszem z ostrzeżeniem implicit-int

add_and_round(a,b) double a,b; { return (int)(a+b+0.5); } - tak, właśnie deklaracja typów parametrów przed klamerkami

zkubinski napisał(a):
  • sam pamiętam, jak kompilator przy funkcji void dopuszczał wartość zwracaną - zgodziłbym się, żeby niewłaściwie użyte return było traktowane jako błąd, a nie uwaga - ale ze względu na kompatybilność wsteczną z językiem C, kompilatory wypluwają tylko uwagę

Chrzani waść, powiedz mi jaki kompilator pozwoli ci zwrócić jakąś wartość kiedy funkcja oznaczona jako void

4

panowie po co się powstrzymywać, taki zróbmy error handling jak już to nam kubiński wychodzi z C.(Jak by co to już trochę trolling)

int foo(int bar)
{
    int return_value = 0;
    if (!do_something(bar)) {
        goto error_1;
    }
    if (!init_stuff(bar)) {
        goto error_2;
    }
error_2:
    return 2;
error_1:
    return 1;
return return_value;
}

@zkubinski: zamiast zakłądac n-ty temat i robic kółka weź przeczytaj stary. Osobiście zrobiłem ci krótki refactoring z optionalem.

2
zkubinski napisał(a):

kurde, już mi się pierdzieli - to w końcu kiedy dawać else ?

Wtedy, kiedy jest to potrzebne. Np. jeśli w narzędnym if jest return (albo inny control-statement który opuszcza blok, jak break) to jest niepotrzebne.

0

@Riddle: i reszta...

po tych wszystkich komentarzach, rozumiem, że tylko poniższa sekwencja ma sens - w sensie można to traktować jako wzór do pozostałych funkcji gdzie używane są warunki ?

int fun(int a)
{
    if(warunek){
        return coś;
    }
    
    return coś_innego;
}
2
zkubinski napisał(a):

po tych wszystkich komentarzach, rozumiem, że tylko poniższa sekwencja ma sens

int fun(int a)
{
    if(warunek){
        return coś;
    }
    
    return coś_innego;
}

albo też

int fun(int a)
{
    if(warunek){
        return coś;
    }
    if(warunek){
        return coś;
    }
    if(warunek){
        return coś;
    }
    return coś_innego;
}
zkubinski napisał(a):

w sensie można to traktować jako wzór do pozostałych funkcji gdzie używane są warunki ?

A może zamiast się kierować "wzorami" i generalizować, to rozpatruj każdy przypadek osobno i kieruj się logiką i rozważ control flow każdego przypadku.

3

@zkubinski:

więc jeżeli warunek if coś zwraca za pomocą returna to już nic pod nim nie daję - tj żadnego else ani return ? Pytam, bo chcę się upewnić

Nie, nie, nie, i jeszcze raz nie. Czy wiesz, co robi if/else? Czy wiesz, co robi return? No to wszystko powinno być jasne.

Instrukcji warunkowych — w szczególności if/else — używasz, gdy chcesz mieć różne ścieżki wykonania, tzn.chcesz móc inaczej zareagować w różnych sytuacjach. Tyle, aż tyle, i tylko tyle. Nie stosujesz, jak reagujesz tak samo w różnych sytuacjach. Nie stosujesz, jak nie masz różnych sytuacji. Stosujesz tyle, ile potrzebujesz — jak masz dwie różne sytuacje, to chcesz mieć dwie ścieżki; jak masz trzy, to trzy; a jak siedemnaście, to siedemnaście. Użycie złej liczby ścieżek jest błędem w każdej sytuacji — zarówno jak robisz dwie przy pięciu sytuacjach, jak i gdy robisz pięć przy dwóch.

Potrzebujesz i chcesz minimalnego sprawdzenia, czy jesteś, czy nie w danej sytuacji. Układ warunków:

if (a < 5) {
  return 5;
}
if (a < 10) {
  return a;
}
return 10;

ma sens i jest poprawny — masz trzy sytuacje, które chcesz rozważyć na trzy sposoby, masz trzy przepływy sterowania, wszystko jak trzeba. Można go popsuć na różne sposoby. Kilka z nich omówię, jest od groma innych, których nie poruszę.

Możesz mieć nadmiarowe testy:

if (a < 5) {
  return 5;
}
if (a >= 5 && a < 10) {
  return a;
}
return 10;

czy, analogicznie:

if (a < 5) {
  return 5;
} else if (a < 10) {
  return a;
}
return 10;

Dlaczego to źle? Bo te dodatkowe testy są niepotrzebne, i sprawiają, że czytający kod muszą się zastanowić, czy nie chciałeś jakiegoś innego testu zrobić — takiego, który by nie był niepotrzebnym śmieciem, a faktycznie coś zmieniał. Zabiera to czas, i sprawia, że poprawność kodu jest mniej oczywista.

Możesz mieć martwy kod:

if (a < 5) {
  return 5;
}
if (a < 10) {
  return a;
}
return 10;
// odtąd kod jest martwy
if (a < 20) {
  return 20;
}

Powód jak wyżej — sprawiasz, że ludzie się zastanawiają, po co to tu siedzi. Gdzie się pomyliłeś — czy napisałeś kod bez sensu, czy może zrobiłeś jakiś błąd w warunkach?

Jak masz z tym problemy, to sobie przeanalizuj — czy to debuggerem, czy „ręcznie”, w pamięci — co się dzieje z danymi przy wykonywaniu funkcji. Gdzie wpadają i kiedy, co z nimi funkcja robi. Dobre testy, zwłaszcza parametryczne, też by Ci w tym pomogły, ale…

Riddle Ci to znakomicie opisał:

Riddle napisał(a):

A może zamiast się kierować "wzorami" i generalizować, to rozpatruj każdy przypadek osobno i kieruj się logiką i rozważ control flow każdego przypadku.

2
Althorion napisał(a):

@zkubinski:

Nie, nie, nie, i jeszcze raz nie. Czy wiesz, co robi if/else? Czy wiesz, co robi return? No to wszystko powinno być jasne.

Sądzę, że gość tego nie odróznia. Ma jakis niewyobrażalny dla mnie sposób myślenia ni to nad konglomeratami, nad zespolami przypadkowego kodu *), (nie nazwę tego zbiorem linii, bo zbiór można określić przez podanie formuły, kwantyfikatora) bez separacji zagadnień. Absolwent 4 klasy podstawówki zwykle już umie wyodrębniać abstrakcje, odróżnia kolor figury od jej kształtu itd...

Podnoszenie starych zarzutów ze zmienionymi przykładami (zmiana typu funkcji w przykładzie) - super, żeby się ... właśnie ... dogadać, czy udowodnić samemu sobie zwycięstwo nad hordami złosliwych - to też majstesztyk, ale innego rodzaju

*) akurat wyjątkowo, pachnie jak uzyskane w krwi, trudnie i znoju, w pocie czoła, a nie prosta wklejka głupawki z googla - jak większość problemów na 4p. To jest dla mnie niezywkłe

4
zkubinski napisał(a):

Jak w temacie. Ciągle mi zarzucacie, że nie znam podstaw itp itd... no to rzucam pierwszy lepszy przykład z brzegu którym się zająłem - tak, zaraz powiecie, że zaczynam od d... strony, a nie od początku, możliwe, że tak ale tym przykładem chcę udowodnić, że ile by podręczników do podstaw nie przeczytał to i tak wszystkiego się w nich nie znajdzie. Może tutaj znajdzie się jakieś wyjaśnienie z przykładem

Zacznę od kodu który napisałem w wątku

Przypomnę kod

int SettingsFile::readSettings()
{
    QFile readFileJson;

    readFileJson.setFileName(QString("settings.json"));

    if(!readFileJson.open(QIODevice::ReadOnly | QIODevice::Text)){
        qInfo()<< "nie mozna odczytac pliku";

        return 2; //numer błędu
    }
    else{
        QByteArray data;
        data = readFileJson.readAll();

        return 0; //numer informujący, że coś się powiodło
    }

    return -2; //nieprzewidzany wyjątek...
}

niejaki @_13th_Dragon zarzucił mi, że źle zwracam wartość za pomocą return ok. możliwe, że robię to źle

Ano źle, ale nie wiem czy pamiętasz, że pozycjonowanie returnów było w zasadzie najmniejszym problemem w tamtym kodzie. Ta funkcja nadal nie wiadomo co robi (nazwa nie zgadza się z implementacją), zwraca magiczne wartości, ale teraz przynajmniej nie obcina zbioru wartości do true/false...

ale czytając dokumentację

  1. https://en.cppreference.com/w/cpp/language/return
  2. https://www.w3schools.com/cpp/cpp_function_return.asp
  3. https://www.programiz.com/cpp-programming/return-reference
  4. https://www.digitalocean.com/community/tutorials/return-array-in-c-plus-plus-function

Tylko pierwszy link można uznać za dokumentację w C++. Ponadto, gdybyś wykazał minimum chęci i przeczytał posty, to byś zauważył, że nie byłeś odsyłany do dokumentacji (tak jak to było w przypadku wcześniejszych pytań o Qt, na które dokumentacja Qt obszernie odpowiadała), tylko do książek. Ewentualnie kursów, tylko tutaj potrzebny jest przesiew.

natykam się, że tak to ujmę - na standardowe użycie - i to dotyczy DOSŁOWNIE KAŻDEGO PODRĘCZNIKA DO PODSTAW - nikt w tych rozważaniach nie skupia się na różnych przypadkach użycia return - co ciekawe nawet inni mają problem z poprawnym zwróceniem wartości

  1. https://stackoverflow.com/questions/1735038/why-not-all-control-paths-return-a-value-is-warning-and-not-an-error
  2. https://stackoverflow.com/questions/1734927/compare-characters-at-the-end-of-the-string-c
  3. https://stackoverflow.com/questions/67284316/non-void-function-does-not-return-a-value-in-all-control-paths-in-c

Link 1: nie ma kodu, więc ciężko się odnieść (pytanie linkuje do innego kodu, który jest poprawny)
Link 2: kompilator poprawnie zauważa brak pewności natrafienia na return
Link 3: kompilator poprawnie zauważa brak pewności natrafienia na return

Niespecjalnie rozumiem jaki jest cel przywoływania tych linków. Owszem, nie jesteś wyjątkowy w skali świata, inni też mogą mieć podobny problem.

Mając na uwadze powyższe, bezzasadne są zarzuty, że nie znam podstaw

🙄🙄🙄

  • dla mnie użycie na przykład return w różnych przypadkach wynika bardziej z doświadczenia programistycznego, aniżeli z oczytania się książkami od podstaw.

Wynika bardziej z przenalizowania potencjalnych ścieżek wykonania funkcji. A jeśli ich jest za dużo, to mogę ponowić zalecenie lektury Clean Code 🙃

Teraz czas na przykłady uwag od kompilatora

nawet rada @_13th_Dragon aby usunąć else nic nie daje (poniżej screeny z kompilatora, gdyż chcę pokazać żółte uwagi)

  1. Screen 1
    screenshot-20221221092350.png

  2. Screen 2
    screenshot-20221221092602.png

  3. Screen 3 - dlaczego poniżej nie ma uwagi ?
    screenshot-20221221092729.png

WTF. Już pomijam, że mylisz IDE i kompilator, ale nie zastosowałeś się do rady Dragona i masz czelność mówić, że błędnie radzi.

na koniec chcę dodać - TYLKO KULTURALNA merytoryczna rozmowa, BEZ bluzg, tzw. wycieczek osobistych i nic nie wnoszących krótkich zwrotów

W backseat moderating baw się gdzie indziej.

typu wróć do podstaw, doucz się, pomyśl itp. bo to nie prowadzi do niczego, niczego nie wnosi i w takich warunkach nie da się nabyć poprawnej wiedzy aby pójść do przodu

No tak, nie dziwi mnie to od człowieka, który wczoraj pisał "rzucacie się z wątkami na człowieka, że nie zna podstaw bo chce iść dalej". Rzecz w tym, że w twoim przypadku nie są to nicniewnoszące dyrdymały, tylko rady, których zastosowanie wyszłoby ci na dobre.

takich rozmów NIGDY nie toleruję

Wiesz gdzie są drzwi. 🚪

bo jak sam wątek wskazuje, wszystkich możliwych przypadków i pełnej wiedzy o programowaniu dowolny autor podręcznika nie opisze, a w zasadzie nie wyczerpie - dlatego potrzebna jest wymiana wiedzy i doświadczenia między nami.

A jednak w dużej mierze wyczerpują. Rzecz w tym, że aby czerpać korzyści z wymiany wiedzy to trzeba się tą wiedzą wymieniać. W każdym wątku, który odwiedziłeś/stworzłeś dostajesz kompetentne rady, ale nic sobie z nich nie robisz. Ponadto zwyczajnie porywasz się na problemy przerastające twój obecny poziom umiejętności.

0

Kompilator teoretycznie mógłby niejawnie wkładać do rejestru RAX, wartość zero jakby się nie dało return, ale w przypadku jak się nie da nic, to zostaną zwrócone śmieci, jakieś przypadkowe dane.

W sumie w assemblerze to pierwszy błąd jaki można doświadczyć to zapomnienie wyzerowania jakiegoś rejestru, albo np. korzystania z dzielenia i niewyzerowanie rejestru reszty z dzielenia, a ta potem bierze udział w następnych operacjach dzielenia, czego wysokopoziomowo nie trzeba wykonywać i człowiek dopiero analizując w debuggerze się chwyci za głowę, zakładając że chciało się wykonać dzielenie całkowite.

Ale kompilator łatwo może wychwycić taki problem i lepiej żeby jawnie był rozwiązany.

1

Mam pewien sposób jak to wytłumaczyć @zkubinski (przynajmniej mnie tak się wydaje), wystarczy narysować "strzałki wykonania":
screenshot-20221221180902.pngscreenshot-20221221180913.pngscreenshot-20221221180928.png
zasada jest prosta, na warunku rozgałęzienie na TAK - czerwony oraz NIE - niebieski, jak idzie konsekwentnie to zielony.
Więc od razu widać gdzie jest problem.

2
_13th_Dragon napisał(a):

Mam pewien sposób jak to wytłumaczyć @zkubinski (przynajmniej mnie tak się wydaje), wystarczy narysować "strzałki wykonania":

Ciekawe, czy skutecznie.
Sześcio-siódmoklasista, i to bez jakiegoś genu hackera, kuma if a takich trzylinijkowcach

(na stronie: może myślenie if-akcja będzie skuteczniejsze, a nie if-return ???, z abstrakcją "akcja" )

2

Po prostu twój kod nie obsługuje wszystkich ścieżek

jak sobie to rozrysujesz to będzie ci łatwiej to dostrzec

int test(int x)
{
	if (x == 1)
	{
		return x;
	}
}

screenshot-20221221190827.png

1 użytkowników online, w tym zalogowanych: 0, gości: 1