2012-10-25 15 views
7

Możliwe Duplikat:
Parameter evaluation order before a function calling in CZła wyjściowy podczas pracy kod C

W poniższym kodzie że oczekuje się, że wyjściowa wynosi 20 i 76, lecz zamiast 75 i 21 nadchodzi jako wyjście. Proszę wyjaśnić, dlaczego tak jest.

#include<stdio.h> 

    unsigned func(unsigned n) 
    { 

     unsigned int a =1 ;   
     static unsigned int b=2;   
     a+=b; b+=a;   
     { 

     unsigned int a=3;   
     a+=b; b+=a;   
     } 
     //printf("%d %d ",a,b); 
     return (n+a+b);   
    } 
    int main() 
    { 
     printf("%d %d\n",func(4),func(5)); 
     return 0; 
    } 
+0

nie potwierdziły, ale ja podejrzewam to: http://stackoverflow.com/questions/376278/parameter-evaluation-order-before-a-function-calling-in-c – Mysticial

Odpowiedz

10

oczekuje się, że func(4) zostanie wywołany przed func(5), ale przeciwnik dzieje się z twoim kompilatorem. Kolejność oceny parametrów funkcji to nieokreślona według standardu C. Zatem kompilator jest wolny, wybierz funkcję, która ma zostać wywołana jako pierwsza. Tak więc w różnych przebiegach można zaobserwować różną kolejność wywołań funkcji, choć jest bardzo mało prawdopodobne, aby tak się stało z tym samym kompilatorem.

+0

Wow. W ten sposób renderowane są wszystkie funkcje w stylu printf i prawdopodobnie inne, które nie są przenośne. – SomeWittyUsername

+4

@icepack dlaczego tak uważasz? Jeśli standard nie wymaga określonego zamówienia i zamierzasz napisać kod, który opiera się na * nieokreślonym * zachowaniu *, oznacza to, że twój * kod * nie jest przenośny, a nie * printf() *. –

+0

Jest to dobrze opisany scenariusz zwany "efektem ubocznym funkcji", który może wystąpić w prawie każdym języku i należy go unikać. http://stackoverflow.com/a/13063692/986760 – fayyazkl

1

Argumenty są przekazywane na stos w odwrotnej kolejności. Wydaje się, że w implementacji kompilatora func(5) jest wywoływana przed func(4).

3

Kolejność oceny func (4) i func (5) nie jest zdefiniowana przez standard (y) C.

2

Kolejność oceny ekspresji jest unspecified behaviour stąd func(4) i func(5) można nazwać w innej kolejności, jak powinien

może chcesz odwiedzić go więcej

Compilers and argument order of evaluation in C++

Parameter evaluation order before a function calling in C

+0

Masz na myśli nieokreślone. Program wykazuje nieokreślone zachowanie, ale nie wykazuje niezdefiniowanych zachowań, o ile mogę to stwierdzić. ("Kolejność oceny desygnatora funkcji, rzeczywistych argumentów i podwyrażeń w obrębie rzeczywistych argumentów jest nieokreślona" C99 6.5.2.2:10) –

+0

@Pascal: Tak, masz rację .. Miałem na myśli to, że faktycznie – Omkant

1

Kolejność oceny może być przyczyną. Bo

//printf("%d %d\n",func(4),func(5)); 
     printf("%d \n",func(4)); 
     printf("%d \n",func(5)); 

drukuje

20 
76 
0

func (5) jest uzyskiwanie wykonywane najpierw:

wartości zmiennych po wykonaniu func (5):

a = 3 
b = 13 
func(5) = 21 

Ponieważ b jest statyczne, wartości po wykonaniu func (4):

a = 14 
b = 57 
func(4) = 75 
0

Kod jest prosty i pamiętaj, że zmienne static zachowają swoje wartości między wywołaniami funkcji.

W programie, z powodu swojej kompilator (czyli kompilator konkretne, zdefiniowane przez nie standardów):

func(5) wykonywany jest pierwszy: który zwraca 21 .. wyjaśnienie:

unsigned func(unsigned n) /*first with 5*/ 
    { 

     unsigned int a =1 ;   
     static unsigned int b=2;   
     a+=b; b+=a;  // a = 3, b = 5 
     { 

     unsigned int a=3;   
     a+=b; b+=a;  // a = 8, b = 13 
     } 
     //printf("%d %d ",a,b); 
     return (n+a+b);  // 5 + 3 + 13 = 21. 
    } 

func (4) jest wykonany Następnie

wyjaśnienie:

unsigned func(unsigned n) /*first with 5*/ 
    { 

     unsigned int a =1 ;   
     static unsigned int b=2;   
     a+=b; b+=a;  // a = 14, b = 27 
     { 

     unsigned int a=3;   
     a+=b; b+=a;  // a = 30, b = 57 
     } 
     //printf("%d %d ",a,b); 
     return (n+a+b);  // 4 + 57 + 14 = 75(which is printed first). 
    } 

Stąd wyjściowego.

0

Jest to dobrze znany termin nazywany "efektami ubocznymi funkcji". Zmieniasz zmienną wewnątrz funkcji, wywołujesz funkcję i polegasz na instrukcji używającej zmiennej, która oczekuje, że już się zmieniła. Zasadniczo należy tego unikać i nie jest to dobre podejście.

Lepszym rozwiązaniem alternatywnym w takim scenariuszu jest funkcja połączenia i zapisanie wartości zwracanych, a następnie użycie ich w printf lub wykonanie dwóch różnych wywołań printf.

side effects