Prevent user passing negative numbers to a function accepting unsigned int
Asked Answered
G

3

5

So here's the code:

int create_mask(unsigned b, unsigned e)
{
  unsigned int mask=1;

  if(b<e || b<0 || e<0)
  {
    printf("Wrong values, starting bit can't be smaller than ending.\n");
    printf("Both got to be >= 0.\n");
    exit(EXIT_FAILURE);
  }
  while(b>0)
  {
    printf("%u\n", b);
    mask<<=1;
    if(b>e)
      mask|=1;
    b--;
  }

  return ~mask; /* negates mask for later purpose that is clearing corresponding bits */
}

Function creates mask for some bit operations, but should take two unsigned ints b and e, both non-negative. Question is how to prevent user input of negative numbers? When function is called with (-1,0) it start the loop, and shoult exit with error.

Grommet answered 2/9, 2013 at 13:54 Comment(9)
But unsigned numbers are never negative, so what does this mean?Altheaalthee
In first place, don't let the function to be called with (-1, 0). Input a string, then convert it to an unsigned integer using strtoul(). It will report an error if the number was negative.Jejune
@harold An implicit conversion from signed to unsigned happens, it's interpreted modulo 1 << width, where width is the number of bits in an unsigned int.Jejune
the signed int -1, when interpreted as a unsigned int will be equal to the maximum value. So it's not less than e, or less than 0.Mabelmabelle
@Mabelmabelle Not necessarily, only if the machine uses a 2's complement representation for negative numbers.Jejune
@H2CO3 so i wrap my function with another function that checks if first char is '-' and proceeds accordingly, right?Grommet
@H2CO3 yes .. and then it's not negative anymore. Problem solved.Altheaalthee
And it does. When you're passing the b = -1 to the function you should trigger the condition at start and exit with EXIT_FAILURE value. But the problem is that the input values defined as unsigned int's which means that the b will be equal to the maximum value available to the unsigned int type on your system. Perhaps, the problem in something different than that?Rianon
@Grommet basically, yes.Jejune
J
5

You could just input a string, check if it contains a '-' character, and yield an error if it does. Else you convert it to an unsigned integer and proceed on. (Reading as a string then converting with strtoul() is preferred over using scanf() anyway, especially while you aren't aware of all of the quirks of scanf().)

char buf[LINE_MAX];
fgets(buf, sizeof buf, stdin);

if (strchr(buf, '-') != NULL) {
    fprintf(stderr, "input must be non-negative!\n");
    exit(-1);
}

unsigned int n = strtoul(buf, NULL, 0);
Jejune answered 2/9, 2013 at 14:13 Comment(3)
sscanf(buf, "%lu", &n); will also do the conversion, but I think strtoul is better :)Wallacewallach
@Wallacewallach It's not a coincidence I've used (and suggested) using strtoul() instead of scanf().Jejune
If you are going to redesign the interface, then it seems far more sensible to specify an int instead of a string. Then you could just assert or throw if the value is <= 0 or < 0.Antenna
Z
2

Edit:

you can take the long int input and then checks input is in between 0 to ending range of unsigned int .if so then assign to your variable else rise an exception to the user ,you should only give unsigned numbers as input.

long int input;
unsigned int valid_input;

scanf("%ld",&input);
if((0<= input) && (input <= 4294967295))
valid_input= (unsigned int)input  ;
else
printf("Unvalid input\n");

As H2CO3 said. reading input into string and checking for first literal if it is not minus then convert into unsigned integer would be preferable rather than the below method. because half of the part unsigned integers not covered.

you can get the input into int and then if it is non negative then proceed .if it is negative rise an exception to the user ,you should not give negative input.

Zrike answered 2/9, 2013 at 13:58 Comment(6)
But this will make it impossible to use certain high unsigned values (which would overflow to the negative half of the range of int when a conversion from unsigned to signed happens. And signed integer overflow is undefined behavior anyway, so this cannot possibly be a correct solution.)Jejune
Exactly, that's the problem.Grommet
@Grommet Again, see my first comment on your question.Jejune
@Grommet However those numbers are in fact by definition equal to the negative numbers. - So when you ask for the exclusion of negative numbers you are in a sense also asking for the exclusion of the high unsigned ints.Mabelmabelle
@H2CO3 there would be another choice.checking of return status of scanf. while scaning if you did not get unsigned integer then you might get zero. as return value.Zrike
@Zrike Well, scanf() doesn't bail out if it encounters a negative number. It will scan a signed integer, then convert it to an unsigned one, and report success.Jejune
A
0

Take a look at this: Stopping function implicit conversion

I was able to adapt it to your issue, and it stops the program from linking. The info in the above thread seems partially incorrect because the example compiled fine. It failed to link because there was not a template specialization defined. I'm actually a little surprised that the following worked for the int vs unsigned int.

template <class T>
void foo(const T& t);

template <>
void foo<unsigned int>(const unsigned int& t)
{

}

int main(){
  foo((unsigned int) 9); // will compile and link
  unsigned int value(5);
  foo(value);// will compile and link
  foo(9.0); // will not link
  foo(-9); // will not link
  return 0;
}

I think that you might be over thinking this though. Is it really a problem? Would it be better to make your id type an int to begin with? Is there a min/max id that avoids the large numbers that could be mistaken for a twos compliment? This seems like an unfortunate issue with the language that it doesn't provide any easy way to stop an implicit cast.

I tested the example with Visual Studio 2010. Additionally, I didn't have the time to write a test class so if it interests you then you'll have to adapt the example to a foo class to see if it works with a constructor of a class, or if there is another way to use templates to do this. Based on the other answers, and my experience I don't think that you are going to find an easy way to do what you want.

Antenna answered 20/1, 2014 at 20:59 Comment(1)
Thank you for an answer, but question is tagged C, strictly C.Grommet

© 2022 - 2024 — McMap. All rights reserved.