2013-10-02 17 views
6

Mam struct, który zawiera ciąg i długości:printf zmiennej String Długość Specyfikator

typedef struct string { 
    char* data; 
    size_t len; 
} string_t; 

Który jest wszystko cacy. Ale chcę mieć możliwość wyprowadzania zawartości tej struktury przy użyciu funkcji podobnej do printf. data może nie mieć terminatora nul (lub mieć go w niewłaściwym miejscu), więc nie mogę po prostu użyć %s. Ale specyfikator %.*s wymaga int, a ja mam size_t.

Pytanie brzmi teraz, w jaki sposób mogę wypisać ciąg znaków przy użyciu printf?

+7

Można * przekonwertować * wartość 'size_t' na' int', pod warunkiem, że wartość pasuje ... –

+3

@KerrekSB Cóż, jeśli długość nie mieści się w 'int', która będzie jedną ciekawą' printf' zadzwoń :-)) Powinien jednak sprawdzić, ponieważ może przepełnić. – cnicutar

+6

Jeśli 'data' może zawierać znaki niedrukowalne (jak znak null), nie chcesz w ogóle'% s'. Napisz pętlę. –

Odpowiedz

3

Prostym rozwiązaniem byłoby po prostu być w użyciu niesformatowany wyjściowa:

fwrite(x.data, 1, x.len, stdout); 

To jest rzeczywiście zła forma, ponieważ fwrite nie może napisać wszystko, więc powinien on być stosowany w pętli;

for (size_t i, remaining = x.len; 
    remaining > 0 && (i = fwrite(x.data, 1, remaining, stdout)) > 0; 
    remaining -= i) { 
} 

Pamiętaj, że x.len jest nie większy niż SIZE_T_MAX.

+0

+1 miał zamiar rzucić to w siebie. Trudno uzyskać znacznie prostsze. – WhozCraig

+0

Ale jeśli chciałem użyć czegoś takiego jak snprintf, to nie działałoby tak dobrze. W takim przypadku mógłbym po prostu skopiować dane, wolałbym jednak użyć innych specyfikatorów formatowania (np. '% I'). –

+0

@drderp: Nie rozumiem. Jak użyłbyś 'snprintf'?Możesz użyć 'memcpy' do zapisania w pamięci zamiast w pliku ... –

1

jak mogę wyjście ciąg printf?

W jednym wywołaniu? Nie możesz w żaden znaczący sposób, ponieważ mówisz, że możesz mieć terminatory zakończone w dziwnych miejscach. Ogólnie rzecz biorąc, jeśli Twój bufor może zawierać niedrukowalne znaki, musisz dowiedzieć się, jak chcesz drukować (lub nie) te znaki podczas wyprowadzania łańcucha znaków. Napisz pętlę, przetestuj każdy znak i wydrukuj go (lub nie) zgodnie z logiką.

11

Zakładając, że łańcuch nie ma żadnych wbudowanych znaki NUL w nim, można użyć %.*s specyfikator po odlewania size_t do int:

string_t *s = ...; 
printf("The string is: %.*s\n", (int)s->len, s->data); 

to też przy założeniu, że długość łańcucha wynosi mniej niż INT_MAX. Jeśli masz ciąg dłuższy niż INT_MAX, masz inne problemy (wydrukowanie 2 miliardów znaków zajmie trochę czasu).

+0

mało prawdopodobne, ale OP * może * być ukierunkowane na wbudowane lub historyczne urządzenie z 16-bitowym 'int' – user4815162342

+0

Czy to naprawdę najlepszy sposób na zrobienie tego? Kiedy po raz pierwszy zauważyłem zachowanie, moje pierwsze pytanie brzmiało: "Dlaczego tak nie jest? Size_t"? –

+0

@JeremyRodi: Nie jestem pewien, ale domyślam się, że używa on 'int' zamiast' size_t', ponieważ jest on przeznaczony do wstecznej zgodności z kodem, który został napisany przed standaryzacją języka C, zanim jeszcze istnieje typ 'size_t'. –

Powiązane problemy