stdint types and conversion...

S

santosh

Hello all,

Conversion macros along the name of INT8_C, INT16_C etc, are defined in
stdint.h to convert their argument into suitable representations for
their corresponding types, i.e. int8_t, int16_t etc.

My questions are:
1. Should the conversion macros be used even when assigning from a
variable of the same type?

2. Why are no such macros provided for int_fast8_t etc. as well as
int_least8_t etc? Can they be assigned values from other types provided
there are no size mismatches and expect the correct thing to happen?

Thanks.
 
S

Skarmander

santosh said:
Hello all,

Conversion macros along the name of INT8_C, INT16_C etc, are defined in
stdint.h to convert their argument into suitable representations for
their corresponding types, i.e. int8_t, int16_t etc.
These are not *c*onversion macros, they are used to declare *c*onstants of
the appropriate types. "Conversion" implies something is being converted,
which is not the case; the constant will have the appropriate type. Your
other questions follow from this misconception.
My questions are:
1. Should the conversion macros be used even when assigning from a
variable of the same type?
No. In fact, you must *not* use them:

"The argument in any instance of these macros shall be a decimal, octal, or
hexadecimal constant (as defined in 6.4.4.1) with a value that does not
exceed the limits for the corresponding type." [7.8.14, paragraph 2].

A variable of any kind is not (required to be) a constant.
2. Why are no such macros provided for int_fast8_t etc. as well as
int_least8_t etc? Can they be assigned values from other types provided
there are no size mismatches and expect the correct thing to happen?
No. The usual rules apply: you need a cast for values that might not fit,
and it's your responsibility to ensure they fit. (A gross oversimplification
of the actual rules, of course, see any good book on C about implicit and
explicit conversion.)

S.
 
S

santosh

Skarmander said:
These are not *c*onversion macros, they are used to declare *c*onstants of
the appropriate types. "Conversion" implies something is being converted,
which is not the case; the constant will have the appropriate type. Your
other questions follow from this misconception.

If I understand correctly the macros are to be used when assigning
literal constant values to variables of their respective types?
Something like:

....
int8_t i8 = INT8_C(-112);
....
My questions are:
1. Should the conversion macros be used even when assigning from a
variable of the same type?
No. In fact, you must *not* use them:

"The argument in any instance of these macros shall be a decimal, octal, or
hexadecimal constant (as defined in 6.4.4.1) with a value that does not
exceed the limits for the corresponding type." [7.8.14, paragraph 2].

A variable of any kind is not (required to be) a constant.
2. Why are no such macros provided for int_fast8_t etc. as well as
int_least8_t etc? Can they be assigned values from other types provided
there are no size mismatches and expect the correct thing to happen?
No. The usual rules apply: you need a cast for values that might not fit,
and it's your responsibility to ensure they fit. (A gross oversimplification
of the actual rules, of course, see any good book on C about implicit and
explicit conversion.)

S.

Thanks for the clarification.
 
B

Barry Schwarz

Hello all,

Conversion macros along the name of INT8_C, INT16_C etc, are defined in
stdint.h to convert their argument into suitable representations for
their corresponding types, i.e. int8_t, int16_t etc.

My copy of n1124 does not show any such macros. Where did you find
them? Why would they be needed? You define a variable of the desired
type with a simple
int8_t x;
and you can convert an expression to the desired type with a simple
cast
x = (int8_t) said:
My questions are:
1. Should the conversion macros be used even when assigning from a
variable of the same type?

2. Why are no such macros provided for int_fast8_t etc. as well as
int_least8_t etc? Can they be assigned values from other types provided
there are no size mismatches and expect the correct thing to happen?

Thanks.


Remove del for email
 
S

Skarmander

santosh said:
If I understand correctly the macros are to be used when assigning
literal constant values to variables of their respective types?
Something like:

...
int8_t i8 = INT8_C(-112);
...
"The macro INT/N/_C(value) shall expand to an integer constant expression
corresponding to the type int_least/N/_t. [..] For example, if
uint_least64_t is a name for the type unsigned long long int, then
UINT64_C(0x123) might expand to the integer constant 0x123ULL."

The _C macros are necessary because you do not know what types are used to
implement the intN_least_t types, so you would not know how to write down
the constant.

For the exact-width integer types (intN_t) these macros are not necessary,
because you can always write down the appropriate constant: for 8 and 16
bits an integer constant will do, for 32 bits a long constant, and for 64
bits a long long constant (of course, the constant has to fit the range of
the integer).

S.
 
S

Skarmander

Barry said:
My copy of n1124 does not show any such macros. Where did you find
them?

Section 7.8.14. Your search function will not help you here, since these
macros are not mentioned by name.
Why would they be needed?

I provided the answer upthread: you do not necessarily know how to write
down constants of the appropriate type.
You define a variable of the desired
type with a simple
int8_t x;
and you can convert an expression to the desired type with a simple
cast
x = (int8_t)<expression>
This is true, but not relevant to the macros under discussion.

S.
 
S

santosh

Barry said:
My copy of n1124 does not show any such macros. Where did you find
them? Why would they be needed?

The are mentioned in the stdint.h file on P.J. Plauger's Dinkumware
site, (C99 Standard Library Reference).

http://www.dinkumware.com/manuals/reader.aspx?b=c/&h=stdint.html
You define a variable of the desired
type with a simple
int8_t x;
and you can convert an expression to the desired type with a simple
cast
x = (int8_t)<expression>

Thanks for the explanation.
 
S

Skarmander

Skarmander said:
santosh said:
If I understand correctly the macros are to be used when assigning
literal constant values to variables of their respective types?
Something like:

...
int8_t i8 = INT8_C(-112);
...
"The macro INT/N/_C(value) shall expand to an integer constant
expression corresponding to the type int_least/N/_t. [..] For example,
if uint_least64_t is a name for the type unsigned long long int, then
UINT64_C(0x123) might expand to the integer constant 0x123ULL."

The _C macros are necessary because you do not know what types are used
to implement the intN_least_t types, so you would not know how to write
down the constant.

For the exact-width integer types (intN_t) these macros are not
necessary, because you can always write down the appropriate constant:
for 8 and 16 bits an integer constant will do, for 32 bits a long
constant, and for 64 bits a long long constant (of course, the constant
has to fit the range of the integer).

Well, the above is obviously faulty. Poking holes in it is left as an
exercise to the reader. At this stage I don't trust myself enough anymore to
do it.

S.
 
S

santosh

Skarmander said:
santosh said:
If I understand correctly the macros are to be used when assigning
literal constant values to variables of their respective types?
Something like:

...
int8_t i8 = INT8_C(-112);
...
"The macro INT/N/_C(value) shall expand to an integer constant expression
corresponding to the type int_least/N/_t. [..] For example, if
uint_least64_t is a name for the type unsigned long long int, then
UINT64_C(0x123) might expand to the integer constant 0x123ULL."

The _C macros are necessary because you do not know what types are used to
implement the intN_least_t types, so you would not know how to write down
the constant.

For the exact-width integer types (intN_t) these macros are not necessary,
because you can always write down the appropriate constant: for 8 and 16
bits an integer constant will do, for 32 bits a long constant, and for 64
bits a long long constant (of course, the constant has to fit the range of
the integer).

S.

Thanks muchly for the explanation. I understand now.
 
J

Jack Klein

santosh said:
Hello all,

Conversion macros along the name of INT8_C, INT16_C etc, are defined in
stdint.h to convert their argument into suitable representations for
their corresponding types, i.e. int8_t, int16_t etc.
These are not *c*onversion macros, they are used to declare *c*onstants of
the appropriate types. "Conversion" implies something is being converted,
which is not the case; the constant will have the appropriate type. Your
other questions follow from this misconception.
My questions are:
1. Should the conversion macros be used even when assigning from a
variable of the same type?
No. In fact, you must *not* use them:

"The argument in any instance of these macros shall be a decimal, octal, or
hexadecimal constant (as defined in 6.4.4.1) with a value that does not
exceed the limits for the corresponding type." [7.8.14, paragraph 2].

A variable of any kind is not (required to be) a constant.
2. Why are no such macros provided for int_fast8_t etc. as well as
int_least8_t etc? Can they be assigned values from other types provided
there are no size mismatches and expect the correct thing to happen?
No. The usual rules apply: you need a cast for values that might not fit,
and it's your responsibility to ensure they fit. (A gross oversimplification
of the actual rules, of course, see any good book on C about implicit and
explicit conversion.)

I'm not sure what you mean by your last paragraph. When performing
assignment among arithmetic types, there are always automatic implicit
conversions when the types are different.

In all the following cases:

-- assigning from a floating point type of greater rank to one of
lesser rank

-- assigning from a floating point type to any integer type

-- assigning from an integer type to a floating point type

....if the value of the original is outside the range of values
representable in the destination type, the result is undefined. A
cast, that is an explicit conversion, does not change this. If the
behavior of the conversion is undefined without the cast, it is just
as undefined with it.
 
S

Skarmander

Jack said:
santosh said:
Hello all,

Conversion macros along the name of INT8_C, INT16_C etc, are defined in
stdint.h to convert their argument into suitable representations for
their corresponding types, i.e. int8_t, int16_t etc.
These are not *c*onversion macros, they are used to declare *c*onstants of
the appropriate types. "Conversion" implies something is being converted,
which is not the case; the constant will have the appropriate type. Your
other questions follow from this misconception.
My questions are:
1. Should the conversion macros be used even when assigning from a
variable of the same type?
No. In fact, you must *not* use them:

"The argument in any instance of these macros shall be a decimal, octal, or
hexadecimal constant (as defined in 6.4.4.1) with a value that does not
exceed the limits for the corresponding type." [7.8.14, paragraph 2].

A variable of any kind is not (required to be) a constant.
2. Why are no such macros provided for int_fast8_t etc. as well as
int_least8_t etc? Can they be assigned values from other types provided
there are no size mismatches and expect the correct thing to happen?
No. The usual rules apply: you need a cast for values that might not fit,
and it's your responsibility to ensure they fit. (A gross oversimplification
of the actual rules, of course, see any good book on C about implicit and
explicit conversion.)

I'm not sure what you mean by your last paragraph. When performing
assignment among arithmetic types, there are always automatic implicit
conversions when the types are different.
I'm lying for the sake of convenience and good programming practice. It's
first of all true that you don't need a cast for assignments of the kind
under discussion.

int i = 32767;
char c = i;

The result of this is defined if char is unsigned or char is big enough to
hold the value 32767, otherwise it's implementation-defined. Many compilers
will not issue a warning about this (nor are they required to, of course).
Nevertheless, programmers worth their salt will use an explicit cast here to
confirm they know what they are doing, even if this does not change the
semantics.
In all the following cases:

-- assigning from a floating point type of greater rank to one of
lesser rank

-- assigning from a floating point type to any integer type

-- assigning from an integer type to a floating point type

...if the value of the original is outside the range of values
representable in the destination type, the result is undefined. A
cast, that is an explicit conversion, does not change this. If the
behavior of the conversion is undefined without the cast, it is just
as undefined with it.

Sure. And if the behavior of an arithmetic conversion is defined with a
cast, it is just as defined without it (ignoring possible change of
semantics). Like I said, "gross oversimplification", with a sheen of
misrepresentation, even. I'm bad.

S.
 
J

jaysome

Skarmander said:
Jack said:
santosh wrote:

Hello all,

Conversion macros along the name of INT8_C, INT16_C etc, are defined in
stdint.h to convert their argument into suitable representations for
their corresponding types, i.e. int8_t, int16_t etc.

These are not *c*onversion macros, they are used to declare
*c*onstants of the appropriate types. "Conversion" implies something
is being converted, which is not the case; the constant will have the
appropriate type. Your other questions follow from this misconception.


My questions are:
1. Should the conversion macros be used even when assigning from a
variable of the same type?

No. In fact, you must *not* use them:

"The argument in any instance of these macros shall be a decimal,
octal, or hexadecimal constant (as defined in 6.4.4.1) with a value
that does not exceed the limits for the corresponding type." [7.8.14,
paragraph 2].

A variable of any kind is not (required to be) a constant.

2. Why are no such macros provided for int_fast8_t etc. as well as
int_least8_t etc? Can they be assigned values from other types provided
there are no size mismatches and expect the correct thing to happen?

No. The usual rules apply: you need a cast for values that might not
fit, and it's your responsibility to ensure they fit. (A gross
oversimplification of the actual rules, of course, see any good book
on C about implicit and explicit conversion.)


I'm not sure what you mean by your last paragraph. When performing
assignment among arithmetic types, there are always automatic implicit
conversions when the types are different.
I'm lying for the sake of convenience and good programming practice.
It's first of all true that you don't need a cast for assignments of the
kind under discussion.

int i = 32767;
char c = i;

The result of this is defined if char is unsigned or char is big enough
to hold the value 32767, otherwise it's implementation-defined. Many
compilers will not issue a warning about this (nor are they required to,
of course).

Yet another reason why programmers need tools like PC-lint, which issues
the following warning:

Info 734: Loss of precision (initialization) (31 bits to 7 bits)
 

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,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top