brak "return" w funkcji ktora zwraca wynik

0

Zastanawia mnie kolejna różnica c++ vs pascal(Delphi)
Kompilator c++ "gcc version 11.2.0 (Rev10, Built by MSYS2 project)"

Moja wina: Zapomniałem w funkcji dopisać return , kompilator ostrzegł mnie a ja go zignorowałem bo chciałem zobaczyć co będzie

bool HW::Buu() 
{
  printf("buu!");
}

kompilator nie umieścił na końcu funkcji instrukcji "ret" i procesor "poszedł w krzaki" , w widoku Assemblera widze jak procesor uruchamia kod z pamięci która jest za moja funkcją.

To normalne zachowanie i najlepiej włączyć dodatkową flagę kompilatora aby wszystkie tego typu problemy wyłapać już na etapie kompilacji ? -Werror=return-type

6

To UB jest

Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.

2

To normalne zachowanie i najlepiej włączyć dodatkową flagę kompilatora aby wszystkie tego typu problemy wyłapać już na etapie kompilacji ? -Werror=return-type

To zalezy od ciebie i projektu. Moim zdaniem taką flage można uznać za error. Szczególnie w wiekszych projektach bo tam nie raz warning się zobaczy z którym nikt nic nie robi bo działa. Ale

  1. Jak widzisz warning to nalezy sie nim zainteresować :)
  2. Czy korzystasz z narzedzi typu clang-tidy, cppcheck? One ci to powiny też powiedzieć.

ustal z reszta teamu :)

0

z mojego punktu to zignorowanie takiego ostrzeżenia może nieźle namieszać wiec zastanawiam sie dlaczego taka niska ranga tego problemu

Jak sie w pamięci programu procedury ułożą że nastepna funkcja zrobi "return" to w sumie nie nikt tego nie zauważy
(zakładam że pamięć programu ułożyła się tak jak kod)

bool HW::Buu() 
{
  printf("buu!");
}
void HW::fu1() // prosta funkcja bez parametrów/zależności
{
}  // tutaj bedzie "powrót gdzie wywołano HW::Buu"

Ale nagle mała zmiana w projekcie

bool HW::Buu() 
{
  printf("buu!");
}
void HW::fu_with_params(.... )  // skomplikowana funkcja z zależnościami 
{
  // spora szansa na wyjątek 
} // jest nadzieje ze wróci do miejsca gdzie wywołano  HW::Buu"
void HW::fu1() 
{
}  

I już kaplica

1

To jest w sumie dość ciekawe zachowanie kompilatora. UB jak UB ale mimo wszystko spodziewałbym sie tam ret. Mógłbyś wrzucic link do godbolta z przykładem?

0

https://godbolt.org/z/4xvqoEsve
I nawet pojawia sie problem ;)
Zamiast trzech napisów jest tylko jeden !

Problem skorelowany z flagamim "-Wall -O3 -fPIC"
I wymagana jest wersja kompilatora od 8.0 w gorę

0

Nie brakuje ret został on jedynie zoptymalizowany.
Widzisz sub rsp, 8? zdjęta ze stosu ramka wywołania metody HW::Buu_before() a więc ret
z wywołanej metody call puts@PLT wróci tam gdzie powinna wrócić HW::Buu_before()

1

@_13th_Dragon nie no chyba nie za bardzo. Przecież stos jest w drugą stronę. sub rsp, X to jest "alokacja" pamięci na stosie, więc jeszcze nas oddala od tego retpointera. Co więcej to tak nie zadziała bo call sam w sobie wrzuci na stos adres powrotu, więc nie można jakoś magicznie sprawić że ret z tej funkcji którą wołamy przez call wróci w inne miejsce bo cośtam zrobiliśmy na stosie przed samym callem.

0

Czyli można watek podsumować:

  1. Nieznajomość kompilatora szkodzi !
  2. [Włączenie optymalizacji] + [brak return gdy jest to wymagane] = spodziewaj się problemów w działaniu aplikacji
1
Adamek Adam napisał(a):

Zamiast trzech napisów jest tylko jeden !

Może program wysypał się na pierwszym brakującym returnie.

U mnie kompilator wyemitował w miejscu brakującego returna instrukcję ud2a - i bardzo dobrze :

bool get_bool()
{
}
00000000000019c0 <_Z8get_boolv>:
    19c0:       55                      push   %rbp
    19c1:       48 89 e5                mov    %rsp,%rbp
    19c4:       0f 0b                   ud2a
    19c6:       cc                      int3
    19c7:       cc                      int3
    19c8:       cc                      int3
    19c9:       cc                      int3
    19ca:       cc                      int3
    19cb:       cc                      int3
    19cc:       cc                      int3
    19cd:       cc                      int3
    19ce:       cc                      int3
    19cf:       cc                      int3
0
pms_enable_synaptics napisał(a):

U mnie kompilator wyemitował w miejscu brakującego returna instrukcję ud2a - i bardzo dobrze :

Undefined behavior znaczy, że może stać się cokolwiek.
Który kompilator i z jakimi ustawieniami? clang? Jak widać zmiana ustawień powoduje, że ud2 znika.
https://godbolt.org/z/dE74Mv1xE

0
MarekR22 napisał(a):

Który kompilator i z jakimi ustawieniami?

$ c++ --version
OpenBSD clang version 13.0.0
Target: amd64-unknown-openbsd7.1
Thread model: posix
InstalledDir: /usr/bin
$

Clang na OpenBSD 7.1 <3

0

Pytanie odnośnie zasiegu "-Wall -Wextra -Werror (gcc/clang), /W4 /WX (msvc)"

Czy można dla jednego pliku .H wyłączyć "-Werror" ?

Używam https://github.com/dtschump/CImg i CImg.h to 1001 warningów

#pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wmisleading-indentation"
    #pragma GCC diagnostic ignored "-Wunknown-pragmas"
    #pragma GCC diagnostic ignored "-Wclass-memaccess"
    #pragma GCC diagnostic ignored "-Wmisleading-indentation"
    #pragma GCC diagnostic ignored "-Wchar-subscripts"
    #include <cimg/CImg.h>
#pragma GCC diagnostic pop
0

Tak można dla plików ale częściej stosuje się to dla całych modułów. czyli załóżmy struktura katalogów w src jest taka
Controllers
Models

W controllers, models sa budowoane z osobna i w cmake są ustawione inne flagi.

tu masz przykład dla cmake dla konkretnie jednego pliku.
https://stackoverflow.com/questions/13638408/override-compile-flags-for-single-files

3

Zamiast włączać na ślepo wszystkie warningi możesz zrobić -Werror=return-type.
Tu masz jak wyłączyć niektóre warningi dla wybranych bloków kodu:

IMO to nie jest "UB" tylko jakiś dramat że ten return-type by default nie jest errorem. Kiedyś straciłem z dwa tygodnie szukając błędu z tego powodu.

0
vpiotr napisał(a):

IMO to nie jest "UB" tylko jakiś dramat że ten return-type by default nie jest errorem. Kiedyś straciłem z dwa tygodnie szukając błędu z tego powodu.

To jest z przyczyn historycznych. Kiedyś w C nie było typu void i nie dało się zadeklarować funkcji, która nie zwracałaby żadnej wartości (domyślnym typem jest i był int).

0
Adamek Adam napisał(a):

z mojego punktu to zignorowanie takiego ostrzeżenia może nieźle namieszać wiec zastanawiam sie dlaczego taka niska ranga tego problemu

Z drugiej strony nadgorliwy kompilator jest upierdliwy, bo czasami nie ma racji.

Z trzeciej strony, to jest kolejny przypadek niepotrzebnego UB.
Niezdefiniowana powinna być zwracana wartość, albo powinna być zdefiniowana jako 0, a nie że pozwala się aby procesor zrobił fikołka.

2

Co do typu void - na Unixie V7 nie ma:

$ ed void.c
?void.c
a
void foo()
{
}
.
w
15
q
$ cc -c void.c
void.c:2: External definition syntax
$ ed int.c
?int.c
a
int foo()
{
}
.
w
14
q
$ cc -c int.c
$
2

dokładnie, domyślnym typem jest int - tak jak napisałem

Napiszę tu bo więcej miejsca. W Wikibooks znalazłem cytat

Jeśli nie podamy typu danych zwracanych przez funkcję kompilator domyślnie przyjmie typ int, choć już w standardzie C99 nieokreślenie wartości zwracanej jest błędem.

Niestety bez podanego źródła którym pewnie jest standard C89

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