tags:

views:

191

answers:

6

I wanna print the value of b[FFFC] like below,

short var = 0xFFFC;
printf("%d\n", b[var]);

But it actually print the value of b[FFFF FFFC].

Why does it happen ?

My computer is operated by Windows XP in 32-bit architecture.

A: 

You were expecting to store JUST a 16bit variable in a 32bit-aligned memory... you see, each memory address holds a whole 32bit word (hardware).

The extra FFFF comes from the fact that short is a signed value, and when assigned to int (at the printf call), it got signed-extended. When extending two-complements from 16 to 32bit, the extension is done by replicating the last N bit to all other M-N on it's left. Of course, you did not intend that.

So, in this case, you're interested in absolute array positions, so you should declare your indexer as unsigned.

jpinto3912
+1  A: 

In current compilers we can't use short (16 bit) if write short use 32 bit .
for example i compile same code with gcc4 in Ubuntu Linux 32 bit :

int main(int argc, char** argv)
{
    short var = 0xFFFC;
    printf("%x\n", var);
    printf("%d\n", var);
    return (EXIT_SUCCESS);
}

and output is :

fffffffc
-4

you can see cast short to 32bit normal and use sign extension in 2's complement

SjB
you're conclusion from observation is wrong... short var is 16bits. Do a var++ loop, see where it overflows.
jpinto3912
@ jpinto3912 what is your conclusion ? printf can't show 16bit data ? if this how to `char c = 'c'; printf("%x",c);`
SjB
don't want to down-vote. But: (I) current compilers *can* use short". (II) the question was not about printf, it was about indexing an array with datatype 'short' (... and I got this wrong too at first). (III) printf can show 16bit data. But then the type specifier 'h' is needed, e.g. with '%hx'.
+1  A: 

use %hx or %hd instead to indicate that you have a short variable, e.g:

  printf("short hex: %hx\n", var);     /* tell printf that var is short and print out as hex */

EDIT: Uups, I got the question wrong. It was not about printf() as I thought. So this answer might be a little bit OT.

New: Because you are using var as an index to an array you should declare it as unsigned short (instead of short):

unsigned short var = 0xFFFC;
printf("%d\n", b[var]);

The 'short var' could be interpreted as a negative number.

To be more precise:

You are "underflowing" into the negative value range: Values in the range from 0x0000 upto 0x7FFF will be OK. But values from 0x8000 upto 0xFFFF will be negative.

Here are some examples of var used as an index to array b[]:

short var=0x0000;; // leads to b[0]        => OK
short var=0x0001;  // leads to b[1]        => OK
short var=0x7FFF;  // leads to b[32767]    => OK
short var=0x8000;  // leads to b[-32768]   => Wrong
short var=0xFFFC;  // leads to b[-4]       => Wrong

short var=32767;   // leads to the same as b[0x7FFF]   => OK
short var=32768;   // compile warning or error => overflow into 32bit range
what the reason for b[FFFC] convert to b[FFFFFFFC]?
SjB
it does not convert to b[0xFFFFFFFC]. To be picky: it does not convert at all. It is interpreted/evaluated as b[-4]
+1  A: 

As a refresher on the C's data types available, have a look here. There is a rule, and that concerns the usage of C, some datatypes are promoted to their integral type, for instance

char ch = '2';
int j = ch + 1;

Now look at the RHS (Right Hand Side) of the expression and notice that the ch will automatically get promoted as an int in order to produce the desired results on the LHS (LHS) of the expression. What would the value of j be? The ASCII code for '2' is 50 decimal or 0x32 hexadecimal, add 1 on to it and the value of j would be 51 decimal or 0x33 hexadecimal.

It is important to understand that rule and that explains why a data type would be 'promoted' to another data type.

What is the b? That is an array I presume that has 655532 elements correct?

Anyway, using a format specifier %d is for of type int, the value got promoted to an int, firstly, and secondly the array subscript is of type int, hence the usage of the short var got promoted and since the data size of an int is 4 bytes, it got promoted and hence you are seeing the rest of the value 0xFFFF 0xFFFC.

This is where the usage of casting comes in, to tell the compiler to cast a data type to another which explains in conjunction to Gregory Pakosz's answer above.

Hope this helps, Best regards, Tom.

tommieb75
+1 At long last, an answer that mentions type promotion. After the C question this afternoon where everyone (in question and answers) was using "declared" to mean "defined", I was beginning to despair.
Pascal Cuoq
@pascal: no you are not right about the term "declaration". When you write "short var = 0xFFFC" it is a declaration and a definition and an initialization all at once. In C you have to use "extern short var" to express "declaration only".
@Vokuhila-Oliba: +1 for your comment above! Please check the C FAQ specifically section 1 which covers declarations, definitions in questions 1.11, 1.25 for clarifications.
tommieb75
+7  A: 

short is a signed type. It's 16 bits on your implementation. 0xFFFC represents the integer constant 65,532, but when converted to a 16 bit signed value, this is resulting in -4.

So, your line short var = 0xFFFC; sets var to -4 (on your implementation).

0xFFFFFFFC is a 32 bit representation of -4. All that's happening is that your value is being converted from one type to a larger type, in order to use it as an array index. It retains its value, which is -4.

If you actually want to access the 65,533rd element of your array, then you should either:

  • use a larger type for var. int will suffice on 32 bit Windows, but in general size_t is an unsigned type which is guaranteed big enough for non-negative array indexes.
  • use an unsigned short, which just gives you enough room for this example, but will go wrong if you want to get another 4 steps forward.
Steve Jessop
I had just almost finished typing almost word for word the same except to say that the compiler probably issued a warning to say that 0xFFFC wasn't a valid short value - warnings are there for a reason - do not ignore them.
Dipstick
He could also use the `size_t` type, which is _the type given by the standard to store array indexes_! Seriously, people, how come no one uses `size_t` when they're supposed to?
Chris Lutz
size_t wasn't always around, so many people have old knowledge, or are learning from old books/tutorials/etc. Even on some embedded compilers, you don't get size_t.
McPherrinM
Chris is quite right, I'll edit. The reason I didn't think to suggest `size_t` is probably just that I've been bullied out of it by C++, where the "most correct" type for an index is usually `typename std::something_long<WINDED>::size_type` or something. So you lose the will to live and just use `int` for constants known to be "small". But this is C.
Steve Jessop
A: 

In the subject of your question you have already guessed what is happening here: yes, a value of type short is "automatically extended" to a value of type int. This process is called integral promotion. That's how it always works in C language: every time you use an integral value smaller than int that value is always implicitly promoted to a value of type int (unsigned values can be promoted to unsigned int). The value itself does not change, of course, only the type of the value is changed. In your above example the 16-bit short value represented by pattern 0xFFFC is the same as 32-bit int value represented by pattern 0xFFFFFFFC, which is -4 in decimals. This, BTW, makes the rest of your question sound rather strange: promotion or not, your code is trying to access b[-4]. The promotion to int doesn't change anything.

AndreyT