Promoting unsigned long int to long int

P

pereges

Below , I have just posted some code. Can some one please tell me if
I'm going wrong somewhere with size_t variables ? I noticed that if I
try to check if size_t variable < 0 , then compiler gives a warning.
But there have been situations where my program failed because the
variable assume garbage values.


int parse_sizes(FILE *fp)
{
size_t nvert, ntri;
int rc = 0;

if (fscanf(fp, "%lu%*lu%lu", &nvert, &ntri) != 2)
{
error_report("Error while parsing the file");
rc = 1;
return (rc);
}

if (nvert < MIN_VERTEX_LIMIT || nvert > MAX_VERTEX_LIMIT)
{
error_report("Number of vertices out of range");
rc = 1;
return (rc);
}

if (ntri < MIN_TRIANGLE_LIMIT || ntri > MAX_TRIANGLE_LIMIT)
{
error_report("Number of triangles out of range");
rc = 1;
return (rc);
}

m_ptr->ntri = ntri;
m_ptr->nvert = nvert;

if (m_ptr->ntri != ntri || m_ptr->nvert != nvert)
{
error_report("Number of vertices out of range");
rc = 1;
return (rc);
}

return (rc);
}
 
P

pereges

Below , I have just posted some code. Can some one please tell me if
I'm going wrong somewhere with size_t variables ? I noticed that if I
try to check if size_t variable < 0 , then compiler gives a warning.
But there have been situations where my program failed because the
variable assume garbage values.

int parse_sizes(FILE *fp)
{
size_t nvert, ntri;
int rc = 0;

if (fscanf(fp, "%lu%*lu%lu", &nvert, &ntri) != 2)
{
error_report("Error while parsing the file");
rc = 1;
return (rc);
}

if (nvert < MIN_VERTEX_LIMIT || nvert > MAX_VERTEX_LIMIT)
{
error_report("Number of vertices out of range");
rc = 1;
return (rc);
}

if (ntri < MIN_TRIANGLE_LIMIT || ntri > MAX_TRIANGLE_LIMIT)
{
error_report("Number of triangles out of range");
rc = 1;
return (rc);
}

m_ptr->ntri = ntri;
m_ptr->nvert = nvert;

if (m_ptr->ntri != ntri || m_ptr->nvert != nvert)
{
error_report("Number of vertices and/or number of triangles
out of range");
rc = 1;
return (rc);
}

return (rc);

}
 
V

vippstar

Below , I have just posted some code. Can some one please tell me if
I'm going wrong somewhere with size_t variables ? I noticed that if I
try to check if size_t variable < 0 , then compiler gives a warning.
I explained to you already why this happends.
unsigned integers cannot have values bellow 0, therefore unsigned
integer < 0 is always false.
But there have been situations where my program failed because the
variable assume garbage values.
The variables assume nothing, please clarify.
int parse_sizes(FILE *fp)
{
size_t nvert, ntri;
int rc = 0;

if (fscanf(fp, "%lu%*lu%lu", &nvert, &ntri) != 2)
{
error_report("Error while parsing the file");
rc = 1;
return (rc);
These two lines are useless, just have return 1;
}

if (nvert < MIN_VERTEX_LIMIT || nvert > MAX_VERTEX_LIMIT)
Do you intend to change MIN_VERTEX_LIMIT to a value different than 0
in the future? If so, leave it as is and ignore the warning;
If not, remove nvert < MIN_VERTEX_LIMIT.
{
error_report("Number of vertices out of range");
rc = 1;
return (rc);
}

if (ntri < MIN_TRIANGLE_LIMIT || ntri > MAX_TRIANGLE_LIMIT)
{
error_report("Number of triangles out of range");
rc = 1;
return (rc);
}

m_ptr->ntri = ntri;
m_ptr->nvert = nvert;
What's the type of m_ptr->ntri, m_ptr->nvert?
 
P

pereges

The variables assume nothing, please clarify.

Well, what I mean to say is that if I had a check in place to see if
the value is below 0 then the program could have been gracefully
terminated after displaying proper error message.
 
P

pereges

fscanf will write sizeof(long) number of bytes,
to the place where nvert is.
If size_t doesn't have the same representation as long unsigned,
then you have a problem.

Then what to do in a situation like this ?? or will be better of with
%zu ? I guess that elements the check :

size_t a;
size_t temp;

scanf("%lu", &temp);
a = temp;
if(a != temp)
{
..
}
 
K

Keith Thompson

Joachim Schmitz said:
%z in C99, %lu and a cast (unsigned long) in C89

No, it's "%zu" in C99. (Keep in mind that it's the implementation of
printf(), part of the runtime library, that has to support this, not
the compiler.)
 
K

Keith Thompson

Joachim Schmitz said:
No! To print the address of a use %p

And a cast to void*:

printf("&a = %p\n", (void*)&a);

[...]
%d expects an int, so the scanf reads an int and places it in a char, loos
of precision and sign may occur.

It's not just loss of precision, it's undefined behavior. Suppose int
is 4 bytes. Then the above scanf call tries to store a 4-byte value
in a 1-byte object. It may happen to work if there's nothing stored
in the 3 bytes following ``a'', and if the low-order byte of an int
happens to be at the beginning.

Try this and see what happens:

char arr[4] = { 'w', 'x', 'y', 'z' }; /* assume sizeof(int)==4 */
scanf("%d", &arr[0]);

Now examine the values of arr[0], arr[1], arr[2], and arr[3].

scanf("%d", &a) doesn't convert the int value to char; the compiler
has no way of knowing that a conversion is necessary. It blindly
attempts to store an int value in a char object.

And this ignores the fact that "%d" tells scanf to expect an int*
argument, and you're giving it a char* argument. (Some compilers
might warn you about this.)
 
K

Keith Thompson

pereges said:
I'm sorry I mean while scanning a not printing it :

size_t a;
scanf("%lu", &a);

Is this operation correct ?

No. It will happen to work if size_t happens to be a typedef for
unsigned long on your system, and it's likely to work if size_t
happens to be the same size as unsigned long.

It will blindly attempt to copy an unsigned long value into a size_t
object (there's no conversion). And that's assuming it doesn't choke
on the size_t* argument where an unsigned long* argument is required.
Undefined behavior.
 
P

pereges

No. It will happen to work if size_t happens to be a typedef for
unsigned long on your system, and it's likely to work if size_t
happens to be the same size as unsigned long.

It will blindly attempt to copy an unsigned long value into a size_t
object (there's no conversion). And that's assuming it doesn't choke
on the size_t* argument where an unsigned long* argument is required.
Undefined behavior.

What in your opinion is the best way to perform such range checks ?
 
K

Keith Thompson

pete said:
I also use long unsigned to count lines in a text stream.

I'll just mention that that type is referred to by most programmers,
and by the standard, as "unsigned long" rather than "long unsigned".
The two forms are equivalent, but some of us find "unsigned long" just
a little bit easier to read. (The counterargument is that "long
unsigned" matches the "%lu" printf format -- but then what about
"%ld"?)

If you're working on existing code, you'd be well advised to use the
same order that's already in use.

Not a huge point, but one worth making, I think.
 
P

pereges

I tried to match sizeof(size_t) with sizeof(unsigned short),
sizeof(unsigned long). It is 4 bytes i.e. same as unsigned long int.
 
J

Joachim Schmitz

Keith said:
And a cast to void*:

printf("&a = %p\n", (void*)&a);
Ah, yes, of course
[...]
%d expects an int, so the scanf reads an int and places it in a
char, loos of precision and sign may occur.

It's not just loss of precision, it's undefined behavior.
I wasn't too sure about this, so I didn't mention, thanks for the
clarification.
Suppose int
is 4 bytes. Then the above scanf call tries to store a 4-byte value
in a 1-byte object. It may happen to work if there's nothing stored
in the 3 bytes following ``a'', and if the low-order byte of an int
happens to be at the beginning.

Try this and see what happens:

char arr[4] = { 'w', 'x', 'y', 'z' }; /* assume sizeof(int)==4 */
scanf("%d", &arr[0]);

Now examine the values of arr[0], arr[1], arr[2], and arr[3].

scanf("%d", &a) doesn't convert the int value to char; the compiler
has no way of knowing that a conversion is necessary. It blindly
attempts to store an int value in a char object.

And this ignores the fact that "%d" tells scanf to expect an int*
argument, and you're giving it a char* argument. (Some compilers
might warn you about this.)

Bye, Jojo
 
K

Keith Thompson

pereges said:
I tried to match sizeof(size_t) with sizeof(unsigned short),
sizeof(unsigned long). It is 4 bytes i.e. same as unsigned long int.

So what?

It happens to match on your system. They're still to be thought of as
distinct types.
 
K

Keith Thompson

pereges said:
What in your opinion is the best way to perform such range checks ?

What range checks are you referring to?

Get the types right first, then worry about range checking.
 
J

Joachim Schmitz

Keith said:
No, it's "%zu" in C99. (Keep in mind that it's the implementation of
printf(), part of the runtime library, that has to support this, not
the compiler.)
Oops, I didn_t read properly:
z Specifies that a following d, i, o, u, x, or X conversion specifier
applies to a size_t or the corresponding signed integer type argument; or
that a following n conversion specifier applies to a pointer to a signed
integer type corresponding to size_t argument.

I only read: "z .... size_t", thanks for correction.

bye, Jojo
 
P

pereges

What range checks are you referring to?

Get the types right first, then worry about range checking.

I mean checking if the value of a variable is within some permissible
range eg. an int should always be between INT_MIN and INT_MAX range
 
K

Keith Thompson

pereges said:
I mean checking if the value of a variable is within some permissible
range eg. an int should always be between INT_MIN and INT_MAX range

An int *is* always between INT_MIN and INT_MAX, inclusive. Assuming
no trap representations or padding bits, it's simply impossible for an
int object to have a value outside that range. If you try to check it
yourself:
if (i < INT_MIN || i > INTMAX) ...
the compiler is likely to optimize away the test.

If you're asking about validating input, that's a different matter.

If you have the input in a string, you can use one of the strto*()
functions to convert it to a numeric value. Unlike the *scanf()
functions, the strto*() functions have well-defined behavior on
overflow. See the documentation for details, and feel free to ask
more specific questions if you're still having problems.
 
B

Barry Schwarz

I think you meant (unsigned long)&a ?

But why is this caste needed when you are already using %lu ? Often
when I want to use chars as ints, I don't use any caste. I simply do :

char a;
scanf("%d", &a);

And it works.

No, it only appears to work. It actually invokes undefined behavior.
You have been unlucky in that the undefined has led you to believe the
code is correct.

%d tells scanf to store sizeof(int) bytes starting at the address of
a. Since sizeof a is 1 by definition and sizeof(int) is usually 2, 4,
or, 8, this will cause scanf to store data in memory that is not part
of a. Who knows what that memory is actually part of.

On a little endian system, the low order byte of the int will be
stored in a and future accesses will appear correct. On a big endian
system, the high order byte will be stored in a and unless you enter a
suitably large value a will appear to be 0.

char objects usually do not have any alignment requirements. int
objects frequently do. It is entirely possible for a to be misaligned
for an int.

%d tells scanf that the corresponding argument is a pointer to int.
There is no requirement for int* and char* (the actual type of &a) to
have the same size, the same representation, or even be passed by the
same mechanism.

All told, substitute sucks for works above.


Remove del for email
 
B

Barry Schwarz

I'm sorry I mean while scanning a not printing it :

size_t a;
scanf("%lu", &a);

Is this operation correct ?

It is never correct. It will invoke undefined behavior whenever
sizeof(unsigned long) > sizeof a or
size_t* has different size, representation, or passing mechanism
than unsigned long* or
size_t has different alignment that unsigned long.
If sizeof a > sizeof(unsigned long) you merely get the wrong answer.
If none of the above, it might work.


Remove del for email
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top