Dlaczego linker C++ pozwala na nieokreślone funkcje?

Ten kod C++, być może zaskakująco, drukuje 1.

#include <iostream>

std::string x();

int main() {

    std::cout << "x: " << x << std::endl;
    return 0;
}

x jest to prototyp funkcji, który wydaje się być postrzegany jako wskaźnik funkcji, a konwersje logiczne w C++ w sekcji 4.12 mówią:

4.12 konwersje logiczne [conv.bool] 1 wartość prvalue arytmetyki, unscoped wyliczenia, wskaźnik, lub wskaźnik do typu member może być konwertowane do wartości prvalue typu bool. Wartość zerowa, wartość wskaźnika null, lub wartość wskaźnika elementu null jest konwertowana na false; Dowolna inna wartość to / align = "left" / Dla bezpośredniej inicjalizacji (8.5), wartość prvalue typu std:: nullptr_t można skonwertować do wartości prvalue typu bool; otrzymaną wartością jest false.

Jednakże x nigdy nie jest związana z funkcją. Jak bym się spodziewał, Łącznik C na to nie pozwala. Jednak w C++ nie jest to żaden problem. Czy ktoś może wyjaśnić to zachowanie?

Author: Columbo, 2014-11-25

3 answers

Tutaj dzieje się tak, że wskaźnik funkcji jest domyślnie konwertowany na bool. Jest to określone przez [conv.bool]:

Wartość zerowa, wartość wskaźnika null lub wartość wskaźnika elementu null jest konwertowana na false; każda inna wartość jest konwertowana na true

Gdzie "wartość wskaźnika null" zawiera Wskaźniki funkcji null. Ponieważ wskaźnik funkcji uzyskany w wyniku rozpadu nazwy funkcji nie może być null, daje to true. Możesz to zobaczyć, włączając << std::boolalpha w polecenie wyjścia.

Poniższe powoduje błąd łącza w g++: (int)x;


Odnośnie tego, czy takie zachowanie jest dozwolone, czy nie, C++14 [basic.odr.ref]/3 mówi:

Funkcja, której nazwa pojawia się jako potencjalnie oceniane wyrażenie, jest odr-używana, jeśli jest unikalny wynik wyszukiwania lub wybrany element zestawu przeciążonych funkcji [...]

, która obejmuje ten przypadek, ponieważ x w wyrażeniu wyjściowym jest sprawdzana deklaracja x powyżej i to jest unikalny wynik. Następnie w /4 mamy:

Każdy program powinien zawierać dokładnie jedną definicję każdej Nie-inline funkcji lub zmiennej, która jest odr-używana w tym programie; nie jest wymagana diagnostyka.

Więc program jest źle uformowany, ale nie jest wymagana diagnostyka, co oznacza, że zachowanie programu jest całkowicie niezdefiniowane.

Nawiasem mówiąc ta klauzula implikuje, że żaden błąd łącza nie jest wymagany dla x();, jednak z kąt jakości realizacji; to byłoby głupie. Kurs, który g++ wybrał tutaj wydaje mi się rozsądny.

 29
Author: M.M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-25 21:25:51

X nie musi być "związana" z funkcją, ponieważ w kodzie stwierdziłeś, że taka funkcja istnieje. Kompilator może więc bezpiecznie założyć, że adres tej funkcji nie może być NULL. Aby to było możliwe, musiałbyś zadeklarować funkcję jako słaby symbol, a tego nie zrobiłeś. Linker nie protestował, ponieważ nigdy nie wywołujesz swojej funkcji (nigdy nie używasz jej rzeczywistego adresu), więc nie widzi problemu.

 13
Author: Freddie Chopin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-25 20:59:31

[podstawowe.def.odr] / 2:

Funkcja, której nazwa pojawia się jako potencjalnie oceniane wyrażenie jest odr-używane, jeśli jest unikalnym wynikiem wyszukiwania lub wybranym elementem zbiór funkcji przeciążonych (3.4, 13.3, 13.4), chyba że jest to czysta funkcja wirtualna i jej nazwa nie jest jawna Kwalifikacje.

Stąd, ściśle mówiąc, kod odr-używa funkcji i dlatego wymaga definicji.
Ale nowoczesne Kompilatory zdadzą sobie sprawę, że funkcje dokładnie adres nie jest w rzeczywistości istotny dla zachowania programu, a zatem nie będzie wymagał definicji.

Zwróć również uwagę na to, co [podstawowe.def.ODR] / 3 określa:

Każdy program powinien zawierać dokładnie jedną definicję każdego nie-inline funkcja lub zmienna, która jest odr-używana w tym programie; brak diagnostyki wymagane.

Implementacja nie jest zobowiązana do wstrzymania kompilacji i wydania komunikatu o błędzie (=diagnostic). Może to zrobić. / align = "left" / Innymi słowy, każde działanie jest dozwolone i mamy UB.

 9
Author: Columbo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-25 21:31:49