开发者

Integer to Character conversion in C

Lets us consider this snippet:

int s;
scanf("%c",&s);

Here I have used int, and not char, for variable s, now for using s for character conversion safely I have to make it char again because when scanf reads a character it only overwrites one byte of the variable it is assigning it to, and not all four that int has.

For conv开发者_运维问答ersion I could use s = (char)s; as the next line, but is it possible to implement the same by subtracting something from s ?


What you've done is technically undefined behaviour. The %c format calls for a char*, you've passed it an int* which will (roughly speaking) be reinterpreted. Even assuming that the pointer value is still good after reinterpreting, storing an arbitrary character to the first byte of an int and then reading it back as int is undefined behaviour. Even if it were defined, reading an int when 3 bytes of it are uninitialized, is undefined behaviour.

In practice it probably does something sensible on your machine, and you just get garbage in the top 3 bytes (assuming little-endian).

Writing s = (char)s converts the value from int to char and then back to int again. This is implementation-defined behaviour: converting an out-of-range value to a signed type. On different implementations it might clean up the top 3 bytes, it might return some other result, or it might raise a signal.

The proper way to use scanf is:

char c;
scanf("%c", &c);

And then either int s = c; or int s = (unsigned char)c;, according to whether you want negative-valued characters to result in a negative integer, or a positive integer (up to 255, assuming 8-bit char).

I can't think of any good reason for using scanf improperly. There are good reasons for not using scanf at all, though:

int s = getchar();


Are you trying to convert a digit to its decimal value? If so, then

char c = '8';
int n = c - '0';

n should 8 at this point.


That's probably not a good idea; GCC gives me a warning for that code:

main.c:10: warning: format ‘%c’ expects type ‘char *’, but 
argument 2 has type ‘int *’

In this case you're ok since you're passing a pointer to more space than you need (for most systems), but what if you did it the other way around? Could be crash city. If you really want to do something like what you have there, just do the typecast or mask it - the mask will be endian-dependent.


As written this won't work reliably . The argument, &s, to scanf is a pointer to int and scanf is expecting a pointer to char. The two data type (int and char) have different sizes (at least on most architectures) so the data may get put in the wrong spot in memeory, and the other part of s may not get properly cleared.

The answers suggesting manipulation of the result after using a pointer to int rely on unspecified behavior (i.e. that scanf will put the character value it has in the least significant byte of the int you're pointing to), and are not safe.


Not but you could use the following:

s = s & 0xFF

That will blank out all of the data except the first byte. But in general all these ideas (and the ones above) are bad ideas, since not all systems store the lowest part of the integer in memory first. So if you ever have to port this code to a big endian system, you'll be screwed.

True, you may never have to port the code, but why write unportable code to begin with?

See this for more info:

http://en.wikipedia.org/wiki/Endianness

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜