2012-01-26 14 views
5

jakie napotykają kolejna próba:wiele wartości zwrotu w funkcji

#include <stdio.h> 

// test multiple return                                        
int foo() 
{ 
    return 1,2,3,4,5,6; 
} 

// main entry point                                         
int main(int argc, char* argv[]) 
{ 
    printf("foo returns: %d\n", foo()); 
    return 0; 
} 

skompilować, a następnie uruchomić:

gcc main.cpp -o main 
./main 

Wyniki są mylące mnie:

foo returns: 6 

Pytanie brzmi: dlaczego nie ma błędu czasu kompilacji?

Odpowiedz

10

Ponieważ używasz comma operator: wyrażenie a,b gdzie a i b są arbitralne (zwykle bok-dokonywaniu) sub-wyrażenia myśli: ocena lewą a i wyrzucić swój wynik (tak a jest oceniana wyłącznie na stronie -effects), a następnie oceń b i podaj jako wynik.

Nie można zwrócić kilku rzeczy z funkcji C. Powinieneś zwrócić np. zagregowany (zazwyczaj struct) lub wskaźnik przydzielony dynamicznie sterty.

Co do pytania, dlaczego kompilator nic nie mówi? Ponieważ o to nie zapytałeś. Naprawdę powinien skompilować z gcc -Wall (dla kodu C) lub g++ -Wall (dla kodu C++), a następnie dostać ostrzeżenia:

egor7.c: In function ‘foo’: 
egor7.c:6:13: warning: left-hand operand of comma expression has no effect [-Wunused-value] 
egor7.c:6:15: warning: left-hand operand of comma expression has no effect [-Wunused-value] 
egor7.c:6:17: warning: left-hand operand of comma expression has no effect [-Wunused-value] 
egor7.c:6:19: warning: left-hand operand of comma expression has no effect [-Wunused-value] 
egor7.c:6:21: warning: left-hand operand of comma expression has no effect [-Wunused-value] 
11

W tym kontekście:

return 1,2,3,4,5,6; 

jest rzeczywiście comma operator. Ocenia wszystko między kolejnymi przecinkami (od lewej do prawej) i zwraca ostatnią.

Dlatego zwraca i drukuje 6. Więc tak, to jest poprawny kod. Dlatego nie ma błędu kompilatora. (Chociaż część 1,2,3,4,5 nic w tym przypadku nie robi.)

W językach C i C++ nie można zwracać wielu wartości. Aby to zrobić, musisz użyć struktury lub klasy.

4

W przypadku wątpliwości, należy dzyń:

$ clang++ -Weverything test.cpp 
test.cpp:4:5: warning: no previous prototype for function 'foo' [-Wmissing-prototypes] 
int foo() 
    ^
test.cpp:6:10: warning: expression result unused [-Wunused-value] 
    return 1,2,3,4,5,6; 
     ^
test.cpp:6:12: warning: expression result unused [-Wunused-value] 
    return 1,2,3,4,5,6; 
     ^
test.cpp:6:14: warning: expression result unused [-Wunused-value] 
    return 1,2,3,4,5,6; 
      ^
test.cpp:6:16: warning: expression result unused [-Wunused-value] 
    return 1,2,3,4,5,6; 
      ^
test.cpp:6:18: warning: expression result unused [-Wunused-value] 
    return 1,2,3,4,5,6; 
       ^
6 warnings generated. 

Jak sama nazwa wskazuje , -Weverything aktywuje każde dostępne ostrzeżenie. W ten sposób nie musisz pamiętać grup, w których się znajdują.

Co do wyjaśnień: patrz odpowiedź Mysticial na temat operatora przecinka i jego efektów sekwencyjnych. Jedną z użytecznych występowanie tego operatora jest:

std::list<Item> list = /**/; 
assert(list.size() >= 10); 

auto it = list.begin(); 
for (int i = 0; i < 10; ++i, ++it) { 
    std::cout << "Item " << i << ": " << *it << "\n"; 
} 

Uwaga jak 3rd klauzula pętli for używa operatora przecinek zrobić dwie operacje w jednym rachunku.

Oczywiście taka składnia jest przeważnie anegdotyczna, więc ludzie regularnie się dziwią ...