2013-10-02 3 views
6

У меня есть структура, которая содержит строку и длину:Printf переменной длина строк Тендерного

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

Что все хорошо и денди. Но я хочу иметь возможность выводить содержимое этой структуры с помощью функции printf. data может не иметь нулевого терминатора (или иметь его не в том месте), поэтому я не могу просто использовать %s. Но спецификатор %.*s требует int, а у меня есть size_t.

Итак, вопрос в том, как я могу выводить строку, используя printf?

+7

Вы можете * конвертировать * a 'size_t' в' int', при условии, что значение подходит ... –

+3

@KerrekSB Ну, если длина не подходит в 'int', это будет один интересный' printf' call :-)) Следует проверить, хотя, поскольку он может переполняться. – cnicutar

+6

Если 'data' может содержать символы, не подлежащие печати (например, нулевой символ), вы не хотите'% s' вообще. Напишите цикл. –

ответ

3

простое решение было бы просто использовать неотформатированная выход:

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

Это на самом деле плохой форме, поскольку fwrite не может написать все, поэтому его следует использовать в цикле;

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

Убедитесь, что x.len не больше, чем SIZE_T_MAX.

+0

+1 собирался бросить это в себе. Трудно получить намного проще. – WhozCraig

+0

Но если бы я хотел использовать что-то вроде snprintf, это не сработало бы. Хотя в этом случае я мог бы просто скопировать данные, я бы предпочел использовать другие спецификаторы форматирования (например, '% i'). –

+0

@drderp: Я не понимаю. Как бы вы использовали 'snprintf'?Вы можете использовать 'memcpy' для записи в ячейку памяти, а не в файл ... –

1

Как я могу вывести строку с помощью printf?

В одном разговоре? Вы не можете каким-либо значимым образом, так как вы говорите, что у вас могут быть нулевые терминаторы в незнакомых местах. В общем случае, если ваш буфер может содержать непечатаемые символы, вам нужно выяснить, как вы хотите напечатать (или не) эти символы при выводе вашей строки. Напишите цикл, протестируйте каждый символ и распечатайте его (или нет), как это диктует ваша логика.

11

Предполагая, что ваша строка не имеет встроенные символы NUL в нем, вы можете использовать %.*s спецификатора после отливки size_t Ань int:

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

Это также при условии, что ваша длина строки меньше INT_MAX. Если у вас есть строка длиннее, чем INT_MAX, тогда у вас есть другие проблемы (для печати на 2 миллиарда символов потребуется некоторое время).

+0

не очень вероятно, но OP * может * нацелиться на встроенное или историческое устройство с 16-битным 'int' – user4815162342

+0

Действительно ли это лучший способ сделать это? Когда я впервые заметил поведение, мой первый вопрос: «Почему это не' size_t'? –

+0

@JeremyRodi: Не уверен, но я предполагаю, что он использует 'int' вместо' size_t', потому что он предназначен для обратной совместимости с кодом, который был написан до того, как язык C был стандартизирован, до того, как существовал тип 'size_t'. –

Смежные вопросы