2011-08-17 6 views
12

Po prostu trochę grając z C++. Co naprawdę chcę zrobić, to móc ustawić funkcję z wartościami domyślnymi zdefiniowanymi dla argumentu tablica lub wskaźnik. Aby wszystko było proste, po prostu użyj tablicy. Tak:Wartości domyślne dla argumentów tablicowych

void experimentA(char a[3] = {'a', 'b', 'c'});

kompilator (LLVM GCC 4.2 z GNU99) twierdzi, "że ekspresja". Jest to dość nudne, ale koledzy mówili mi, że tak się dzieje, ponieważ "wartość", którą próbuję przypisać, jest przydzielana statycznie, podczas gdy zmienna, którą próbuję przypisać do (a[3]), jest automatyczna.

Ale nie jestem całkowicie pewien, czy to przypadek, ponieważ jestem w stanie to zrobić:

void experimentB(char a[3] = "abc");

i kompilator tylko ostrzega mnie, że ciąg-dosłownego do char * konwersja jest przestarzała .

Nie rozumiem, jak "abc" różni się zasadniczo od {'a', 'b', 'c'}, aby spowodować tę rozbieżność. Każdy wgląd jest bardzo doceniany!

+0

Pamiętaj, że w "ABC" jest naprawdę { 'a', 'b', 'c', '\ 0'} który pasowałby do tablicy o rozmiarze 4. –

+1

@Doug: Kiedy literał łańcuchowy jest używany do zainicjowania tablicy znaków, nie musi być miejsca na terminator o wartości NULL. Jeśli programista określa dokładną długość, powinien wiedzieć, co robi. –

Odpowiedz

6

Twoi koledzy są w błędzie lub źle Cię zrozumieli.

Pierwszą wskazówką do zrozumienia jest to, że nie można mieć tablicy jako parametru funkcji w C lub C++. Powody są historyczne. Tak więc podczas pisania void experimentA(char a[3] ...) kompilator automatycznie konwertuje go do wskaźnika, tj. void experimentA(char* a ...). Tak więc prawdziwym pytaniem jest, dlaczego "abc" jest odpowiednią wartością domyślną dla a, a { 'a', 'b', 'c' } nie jest. Powodem jest to, jak wyjaśnia kompilator, "abc" jest wyrażeniem, a { 'a', 'b', 'c' } nie jest (jego inicjatorem). Jest kilka miejsc w C++, gdzie możesz użyć inicjalizatora, a gdzie nie. Domyślna wartość parametru jest jednym z miejsc, których nie możesz.

+0

Doskonały. To ma sens. Szkoda, że ​​mogę wybrać tylko jedną z odpowiedzi jako "odpowiedź". –

1

"abc" to wyrażenie, {'a', 'b', 'c'} to inicjator statyczny. Później dopuszczalne jest tylko w deklaracjach zmiennych. Z nieznanych mi powodów argument o wartości domyślnej ma inną regułę gramatyczną, która nie pozwala na inicjowanie statyczne.

Istnieje kilka znaczących zmian w przypadku, gdy inicjalizatory statyczne są dozwolone w C++ 0x, ale nie jestem pewien jak to wpływa na daną sprawę.

4

Gdy używasz literału "abc", jest on przydzielany przez kompilator gdzieś w pamięci, a wskaźnik do jego pierwszego znaku jest używany jako wartość domyślna. Tak więc dla kompilatora kod wygląda tak: void experimentA(char a[3] = 0x12345678);.

W drugim przypadku literał tablicy nie jest przydzielany przez kompilator jako ciąg znaków (co uważam za pewną niespójność w języku).

2

"abc" jest wyrażeniem . Zachowuje się specjalnie, inaczej niż wszystkie inne wyrażenia, gdy jest używane do zainicjowania zmiennej typu array of char.

{'a','b','c'} nie jest wyrażeniem, ale inicjatorem . Dopuszczalne jest tylko składniowe w definicjach zmiennych. Tam, składnia umożliwia albo wyrażenie, albo inicjator bezwyrażenia, ale to nie znaczy, że inicjatory mogą być używane jako wyrażenia w innym miejscu.

+0

+1 za wyjaśnienie prawidłowych przypadków użycia inicjalizatora. Dzięki temu wyjaśniłem kilka dręczących mnie wątpliwości. –

1

Parametr domyślny musi być prawidłowy.

można wywołać

F ("abc")

ale nie

f ({ 'a', 'b', 'c'});

"abc" jest faktycznie adresem w pamięci, a {'a', "b", "c"} oznacza inicjalizację tablicy lub struktury/klasy.

0

Jednym z prostych sposobów na to jest przeciążenie starej funkcji. Na przykład, poniżej symuluje domyślną wartość parametru dla parametru formatu, który jest typu char *:

static string to_string(time_point<system_clock> time) 
{ 
    return to_string(time, "%Y-%m-%d-%H-%M-%S"); 
} 

static string to_string(time_point<system_clock> time, const char* format) 
{ 
    time_t tt = system_clock::to_time_t(time); 

    char str[1024]; 
    if (std::strftime(str, sizeof(str), format, std::localtime(&tt))) 
     return string(str); 
    else return string(); 
}