2015-11-16 3 views
1

printf - прекрасная функция, потому что она помогает вам форматировать вашу строку очень простым способом.Конкатенация строки, как в printf

printf("Player %s has lost %d hitpoints", victim.name, damage); 

Есть ли подобный способ конкатенации и выполнить приведение в «нормальной» строки, как показано ниже:

uint8_t myString = ("Player %s has lost %d hitpoints", victim.name, damage); //SOMETHING LIKE THIS 
+4

'Sprintf()' ваш ответ – Haris

+3

вы хотите [ 'Sprintf()'] (http://linux.die.net/man/3/sprintf)? –

+1

. Идея Джона Кармака для этой функциональности интересна, как реализовано в движке Quake 3: https://github.com/id-Software/Quake-III-Arena/blob/master/code/splines/q_shared.cpp (строка 700). Обратите внимание, что вам нужен достаточно глубокий буфер или смешные вещи могут произойти с вложенными вызовами, и, конечно же, это большой нет-нет, если вы пишете многопоточный код. – szczurcio

ответ

4

C99 в snprintf печатает на строку и гарантирует не переполнения буфера:

char msg[48]; 

snprintf(msg, sizeof(msg), 
    "Player %s has lost %d hitpoints", victim.name, damage); 

snprintf возвращает количество символов, которые были написаны уже строка была достаточно большой. Поэтому, если возвращаемые значения равны или больше размера буфера, строка была усечена.

Это законно передать размер буфера нуля и нулевой указатель, так что вы можете сделать свой собственный выделение путем зондирующего вызова первого:

char *msg; 
int n; 

n = snprintf(NULL, 0, 
    "Player %s has lost %d hitpoints", victim.name, damage); 

msg = malloc(n + 1); 
n = snprintf(msg, n + 1, 
    "Player %s has lost %d hitpoints", victim.name, damage); 

// do stuff with msg 

free(msg); 

На компиляторов GNU, не-sandard функции asprintf будет делать это для вас:

char *msg = asprintf("Player %s has lost %d hitpoints", 
    victim.name, damage); 

// do stuff with msg 

free(msg); 
5

Вы можете использовать sprintf(). Как это

char* myString = malloc(50); 

sprintf(myString, "Player %s has lost %d hitpoints", victim.name, damage); 

Как вы догадались, это означает строки Printf


ли уведомление, что sprintf() требует char*, не uint8_t.


Вы также можете использовать snprintf(). Дополнительным преимуществом является то, что вы можете указать количество символов, которые будут скопированы в строку. Это может предотвратить переполнение буфера.

char* myString = malloc(50); 

snprintf(myString, 50, "Player %s has lost %d hitpoints", victim.name, damage); 
+2

Использовать 'snprintf' вместо этого, когда это возможно. – user694733

+0

@ user694733, thanx .. добавил .. :) – Haris

+0

@Haris Стоит отметить, что в вашем примере snprintf будет писать только 49 символов. Один всегда зарезервирован для нулевого терминатора. – Magisch

2

Попробуйте как этот

char str[MAX_LEN]; 
    sprintf(str,"Player %s has lost %d hitpoints", victim.name, damage); 

, но я не уверен, что это очень безопасно передавать uint8_t* в sprintf вместо char *. (это может быть нарушение ограничений, см. here для получения дополнительной информации о подобной ситуации).

Действительно для большей безопасности вы также можете использовать snprintf.

+0

Вместо этого используйте 'snprintf', если это возможно. – user694733

+0

@ user694733 Вы имеете в виду, потому что там вы можете указать максимальные байты? – Magisch

+0

@Magisch Да, чтобы предотвратить переполнение. – user694733

2
printf("Player %s has lost %d hitpoints", victim.name, damage); 

Если вы хотите сохранить результат в виде строки, а затем распечатать его, есть еще одна функция из того же семейства, доступной под названием sprintf. В вашем случае, использовать его как это:

sprintf(myString,"Player %s has lost %d hitpoints", victim.name, damage); 

Further info on sprintf

Как user694733 отметил, что, как правило, безопаснее использовать snprintf вместо sprintf. Различие между ними состоит в том, что для snprintf вы получите, чтобы определить максимальное количество символов для записи в строку (это включает в себя терминатор символ \0!»Во втором аргументе. More info on snprintf

+0

Использовать 'snprintf' вместо этого, когда это возможно. – user694733

+0

@ user694733 Я добавил обозначение, обсуждая это с моим ответом с благодарностью. – Magisch

4

Каждый предлагая sprintf, но в моем мнение гораздо лучше всегда использовать snprintf прототип функции выглядит следующим образом:.

int snprintf (char * s, size_t n, const char * format, ...); 

Первый аргумент ваша строка буфера, то второй аргумент его максимальная мощность, за которым следует строка спецификатор формата и аргументы.Пример использования:

char str[STR_LEN]; 
snprintf(str, sizeof(str), "Player %s has lost %d hitpoints", victim.name, damage); 

Обратите внимание, что в то время как это никогда не будет ничего противозаконного делать (с помощью sprintf можно произвести неопределенное поведение), если буфер не достаточно долго строка будет усечена, что может привести к каким-то удивительным выходом. Лучше всего проверить результат snprintf, чтобы узнать, сколько символов написано на самом деле (спасибо за то, что он указал на это).

Если вы заинтересованы в возможности писать код, как в вашем вопросе, где струна возвращается к вам из функции форматирования, вы можете найти Кармак va от его idTech3 двигателя интересного: https://github.com/id-Software/Quake-III-Arena/blob/master/code/splines/q_shared.cpp (строка 700). Обратите внимание, что вы должны понимать, как это работает, и его возможные последствия для вложенных вызовов, не говоря уже о проблемах, которые могут возникнуть, если вы должны использовать это в многопоточной среде.

+1

Если не проверен результат 'snprintf()', UB перетекающего буфера с помощью 'sprintf()' теперь подвергает риску код, исходящий с усеченным буфером из 'snprintf()'. Иначе может быть '' Player long_name потерял ''. Лучше всего проверить возвращаемое значение. – chux

+1

@chux Хороший улов, спасибо. – szczurcio

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