Czy w C można podzielić długą instrukcję printf na wiele linii?

86

Mam następujące oświadczenie:

printf("name: %s\targs: %s\tvalue %d\tarraysize %d\n", sp->name, sp->args, sp->value, sp->arraysize);

Chcę to zerwać. Próbowałem wykonać następujące czynności, ale to nie działa.

printf("name: %s\t
args: %s\t
value %d\t
arraysize %d\n", 
sp->name, 
sp->args, 
sp->value, 
sp->arraysize);

Jak mogę to rozbić?

neuromancer
źródło
1
Podano kilka dobrych sugestii, ale żadna z nich nie może być tak jasna ani łatwa do utrzymania, jak tylko cztery oddzielne wywołania printf ().
Clifford
@Clifford: wtedy mógłbyś napisać C ++, żeby cout wyglądał lepiej dla ciebie.
Przetestuj

Odpowiedzi:

173

Jeśli chcesz podzielić literał ciągu na wiele wierszy, możesz połączyć wiele ciągów razem, po jednym w każdym wierszu, na przykład:

printf("name: %s\t"
"args: %s\t"
"value %d\t"
"arraysize %d\n", 
sp->name, 
sp->args, 
sp->value, 
sp->arraysize);
James McNellis
źródło
85
tylko komentując, aby wyjaśnić mało znany fakt w C, że białe znaki między dwoma ciągami znaków to konkatenacja.
Brian Postow
2
@Lundin Posiadanie każdej zmiennej i jej wartości jasno przedstawionej w osobnym wierszu jest dla mnie znacznie łatwiejsze do odczytania. Czy możesz sobie wyobrazić debugera w środowisku IDE, który umieszcza wszystkie zmienne i wartości w jednym wierszu? Nie mogę. (Tak, wiem, że nie umieszcza znaków nowej linii między każdym ciągiem, ale porównuję czytelność kodu źródłowego z czytelnością zmiennych w debugerze)
byxor.
Czy ta konkatenacja jest wykonywana przez preprocesor?
debiut
21

Kompilator C może skleić sąsiednie literały ciągów w jeden, na przykład

printf("foo: %s "
       "bar: %d", foo, bar);

Preprocesor może użyć odwrotnego ukośnika jako ostatniego znaku linii, nie licząc CR (lub CR / LF, jeśli jesteś z Windowsland):

printf("foo %s \
bar: %d", foo, bar);
qrdl
źródło
6
Pierwsza została już zasugerowana, druga cierpi z powodu tego, że pęka, jeśli po znaku „\” występuje spacja ; błąd, który może być kłopotliwy, gdy się pojawi.
Clifford,
1
Żaden z tych dwóch przykładów nie ma nic wspólnego z preprocesorem C.
Dan Molding
@Dan, mój CPP wydaje się rozumieć / (zobacz moją edycję powyżej). Nie jestem pewien, czy jest to standardowe zachowanie.
sigjuice
@Dan Podczas gdy łączenie sąsiednich literałów może odbywać się za pomocą preprocesora lub kompilatora (na ostatnim etapie przed właściwą kompilacją), obsługa kontynuacji linii jest wykonywana przez preprocesor, ponieważ w przeciwnym razie makra wielowierszowe nie mogą zostać zaimplementowane. Zobacz także tutaj - gcc.gnu.org/onlinedocs/cpp/Initial-processing.html
qrdl
2
@qrdl: Mój błąd, masz rację co do drugiego. Kontynuacja linii jest zawsze wykonywana przez preprocesor. Czasami muszę być przypomniał, że jestem nie know-it-all;) ja nadal uważam, że w normalnym przypadku kompilator dołącza literały ciągów znaków, choć.
Dan Molding
20

Tylko kilka innych opcji formatowania:

printf("name: %s\targs: %s\tvalue %d\tarraysize %d\n", 
        a,        b,        c,        d);

printf("name: %s\targs: %s\tvalue %d\tarraysize %d\n", 
              a,        b,        c,            d);

printf("name: %s\t"      "args: %s\t"      "value %d\t"      "arraysize %d\n", 
        very_long_name_a, very_long_name_b, very_long_name_c, very_long_name_d);

Możesz dodać warianty motywu. Chodzi o to, że printf()speficiers konwersji i odpowiednie zmienne są wszystkie ustawione w jednej linii „ładnie” (dla niektórych wartości „ładnie”).

pmg
źródło
Nie ma tu nic funkcjonalnego, ale nowatorski pomysł, którego nigdy wcześniej nie widziałem. Podoba mi się, świetny komentarz @pmg!
rpj
3

De facto standardowy sposób dzielenia złożonych funkcji w C jest na argument:

printf("name: %s\targs: %s\tvalue %d\tarraysize %d\n", 
       sp->name, 
       sp->args, 
       sp->value, 
       sp->arraysize);

Lub jeśli chcesz:

const char format_str[] = "name: %s\targs: %s\tvalue %d\tarraysize %d\n";
...
printf(format_str, 
       sp->name, 
       sp->args, 
       sp->value, 
       sp->arraysize);

Nie powinieneś rozdzielać łańcucha ani używać go \do łamania linii C. Taki kod szybko staje się całkowicie nieczytelny / nie do utrzymania.

Lundin
źródło
3

Nie sądzę, aby użycie jednej printfinstrukcji do wydrukowania literałów łańcuchowych, jak widać powyżej, jest dobrą praktyką programistyczną; można raczej użyć fragmentu kodu poniżej:

printf("name: %s\t",sp->name);
printf("args: %s\t",sp->args);
printf("value: %s\t",sp->value);
printf("arraysize: %s\t",sp->name); 
antoine maboula
źródło