Преобразование int в char* в C, когда использование sprintf слишком дорого
Мне нужно конвертировать int
значение для char
строка, я использовал следующую функцию, где счет имеет тип int
,
void updateScore(){
char str[5] = "0";
sprintf(str, "%d", score);
drawString(str);
}
void drawString5x7(char *string){
while (*string)
drawChar5x7(*string++);
}
Кажется, это работает, за исключением того, что этот фрагмент кода является частью гораздо большей системы, в которой я кодирую видеоигру на микроконтроллере (MSP430) с ограниченным объемом доступной памяти. Я могу обновить счет за один раз до того, как моя игра зависнет и вылетит.
По какой-то причине, когда я добавляю sprintf()
функция (или другие подобные функции, такие как snprintf
, или же asprintf
), он съедает много доступной памяти на MCU.
С sprintf
функции он компилирует в 11407 байт. Если я прокомментирую эту строку, мой код скомпилируется в 4714 байт
Я не слишком знаком с преобразованием int
в char
Струны, однако, я не думаю, что он должен занимать столько памяти. Любое руководство будет высоко ценится.
4 ответа
Вот моя быстрая реализация int
в string
функция:
// buf - string buffer, e.g. 16 bytes
// len - size of buf
// value - integer value
char * i2s( char * buf, int len, int value )
{
char m = 0;
if ( value < 0 )
{
// if ( value == -2147483648 ) return "-2147483648"; // fix for INT_MIN
value = -value;
m = '-'; // minus for negative values
}
buf[len - 1] = 0; // 0 for end of string
for ( int i = len - 2; i > 0; i-- ) // loop from right (last digits) to left
{
buf[i] = '0' + ( value % 10 );
value /= 10;
if ( value == 0 )
break;
}
if ( m ) buf[--i] = m;
return buf + i;
}
Использование:
char my_buf[16];
char * s = i2s( my_buf, sizeof my_buf, 10850 ); // 10850 is the int value
Пять символов - это не много - чтобы покрыть каждое значение целого, вам нужно как минимум 10 цифр + знак + завершающий символ 0, т. Е. 12. Тогда я бы создал массив со степенью двойки, то есть 16:
char str[16];
Тогда вы можете просто закодировать с обратной стороны:
str[sizeof(str)] = 0;
char* pos = str + (sizeof(str) - 1);
int n = score < 0 ? -score : score;
do // do while handles n == 0 correctly!
{
// possible, if all digits are placed one after another
// in ascending order, such as in ASCII (and those based on):
*--pos = '0' + n % 10;
// alternative, portable over all encodings:
//*--pos = "0123456789"[n % 10];
n /= 10;
}
while(n);
if(score < 0)
*--pos = '-';
drawString(pos);
Изменить (глядя на другие ответы (и комментарии), опубликованные во время написания моего):
Выше решение тоже не удастся для INT_MIN
!
Вы могли бы поймать это отдельно (оценка == INT_MIN) - или просто полагаться на то, что это значение никогда не будет достигнуто в любом случае (потому что это не разумно в вашей игре).
Дополнительно: мой вывод выровнен по левому краю! Если вы хотите выровнять по правому краю, вы можете просто поместить дополнительные пробелы в цикл for:
for(char* align = str + 4; pos > align;)
*--pos = ' ';
Имейте в виду, что вы не можете сравнивать произвольные указатели с <
, >
, <=
, >=
! Здесь это возможно, потому что оба указателя указывают на один и тот же массив!
Там уже опубликовано общее решение. В вашем случае, когда известны верхний и нижний пределы, вы можете использовать следующий код:
void updateScore() {
char str[5] = "0"; /* Can hold up to 4 digits. */
int i, div = 1000; /* 10^(length of str - 2). */
int sc = score;
/* Fast-forward to the first non-zero digit */
while (div > sc) {
div /= 10;
}
for (i = 0; div; i++) {
str[i] = ´0´ + sc / div;
sc %= div;
div /= 10;
}
drawString(str);
}
Если вы хотите набрать ноль, вам не нужно быстро переходить к первой ненулевой цифре:
void updateScore() {
char str[5] = "0"; /* Can hold up to 4 digits. */
int i, div = 1000; /* 10^(length of str - 2). */
int sc = score;
for (i = 0; div; i++) {
str[i] = ´0´ + sc / div;
sc %= div;
div /= 10;
}
drawString(str);
}
Вы можете печатать целые числа вручную, например
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
void drawChar ( char c )
{
printf("%c", c);
}
void drawScore(uint16_t score)
{
bool startFound = false;
uint16_t devider = 1000;
while (devider != 0)
{
uint8_t digit = (score / devider);
if (( digit == 0) && (startFound == false))
{
// draw space
drawChar(0x20);
}
else
{
// first digit of score found
startFound = true;
// draw space
drawChar(digit+'0');
}
// move to the next digit
score -= digit * devider;
devider /= 10;
}
}
int main(void)
{
drawScore(1234);
printf("\n");
drawScore(234);
printf("\n");
drawScore(34);
printf("\n");
drawScore(4);
printf("\n");
}
ВЫХОД на терминале Linux.
1234
234
34
4