tags:

views:

193

answers:

5

We currently have some code to extract digits from an int, but I need to convert this to a platform without snprintf, and I am afraid of a buffer overrun. I have started to write my own portable (and optimized) snprintf but I was told to ask here in case someone had a better idea.

int extract_op(int instruction)
{ 
    char buffer[OP_LEN+1];
    snprintf(buffer, sizeof(buffer), "%0*u", OP_LEN, instruction);
    return (buffer[1] - 48) * 10 + buffer[0] - 48;
}

We are using C strings because Speed is very important.

+6  A: 

You don't need to form instruction into a character array for this purpose; you just need to keep "the two top digits", as follows:

int extract_op(unsigned int instruction)
{
    int first = 0;
    int second = 0;
    while(instruction) {
        second = first;
        first = instruction % 10;
        instruction /= 10;
    }
    return first + 10 * second;
}

I think the expression in the return is wrong, but it does mimic what you're doing: ten times the second digit, plus the first one.

I suspect that speed might be even better than what you're getting now, but that's up to you to measure on your specific platform and compiler, of course.

Alex Martelli
Excuse me, but why did you strip all vowels from your locals? (Also, check your loop, you use `first` instead of `frst` right now.)
zneak
@zneak, no real reason, let me edit it to make it sensible again;-).
Alex Martelli
@Ari you might also get improvement by using divmod or equivalent function to compute an update your values
aaa
+2  A: 

Using sprintf should be fine. sizeof type * 3 * CHAR_BIT / 8 + 2 is a sufficiently large buffer for printing an integer of type type. You can simplify this expression if you assume CHAR_BIT is 8 or if you only care about unsigned formats. The basic idea behind it is that each byte contributes at most 3 digits in decimal (or octal), and you need space for a sign and null termination.

R..
`((CHAR_BIT * sizeof(type) - 1) / 3 + 2)` will give a slightly smaller but still safe figure.
caf
Good point. All my code assumes `CHAR_BIT==8` so I typically just use `sizeof(type)*3+2`, which ends up being less cluttered, but if you want to support odd char sizes, your version is less cluttered and a tighter bound.
R..
+1  A: 

So far there's one answer that swaps the last two digits and one that swaps the first two… it looks to me like "%0*u", OP_LEN is forcing the output to a particular width, and the significance of the extracted digits is predetermined by OP_LEN.

Assuming OP_LEN is a macro, we can get 10^(OP_LEN-2) with

#define DIVISOR ( (int) ( 1.e ## OP_LEN * 0.01 ) )

Then, similar to @zneak's answer,

int extract_op( int instruction )
{
    instruction /= DIVISOR;
    int tens = (instruction / 10) % 10;
    int units = instruction % 10;
    return units * 10 + tens;
}

#undef DIVISOR
Potatoswatter
A: 

U can store the digit u are getting into array. THIS ONE WAS THE CODE EXPLAINED BY ALEX. here i am adding some variables.

int a[5];

int extract_op(unsigned int instruction)
{
int i=0;    
int first = 0;
    int second = 0;
    while(instruction) {
        second = first;
        first = instruction % 10;
        instruction /= 10;
    }
    a[i]=first;
}

This is something will work for all integers will have max 5 digits. But still if u want to take dynamic array then u can use link list

Rakesh Gondaliya
A: 

should work also for 0 and <0.

int extract_op( int instruction )
{
  int numd = 1;
  while( instruction /= 10 )
    ++numd;
  return numd;
}