tags:

views:

450

answers:

2

Can anyone explain the following behaviour to a relative newbie...

const char cInputFilenameAndPath[] = "W:\\testerfile.bin";
int filesize = 4584;

char * fileinrampointer;
fileinrampointer = (char*) malloc(filesize);

ifstream fsInputFileStream;
fsInputFileStream.open(cInputFilenameAndPath, fstream::in | fstream::binary);

fsInputFileStream.read((char *)(fileinrampointer), filesize);

for(int f=0; f<4; f++)
{
    printf("%x\n", *fileinrampointer);
    fileinrampointer++;
}

I was expecting the above code to rread the first 4 bytes of the file I just read into memory. In the loop I am just displaying the current byte pointed to by the pointer then incrementing the pointer ready to display the next byte. When I run the code I get:

37

ffffff94

42

ffffffd2

The values are correct but every other value seems to be padded up to a 64 bit number. Because I'm asking it to display the value indicated by a 'char sized' pointer, I was expecting char size results but every other result comes out as a long long. If I asign *fileinrampointer to an unsigned __int8 it leaves me with the value I want (without the leading 1s) which solves the problem, but I'm just wondering if anyone can explain what is happening above?

+2  A: 

You are not asking it to display a value indicated by a char sized pointer, you are asking it to display a hexidecimal integer (%x) using the contents of a char pointer. Not tried it but you could try casting it:

printf("%x\n", (unsigned int)(*fileinrampointer));
Patrick
int won't do it, has to be unsigned.
Adrian Panasiuk
+9  A: 

The expression *fileinrampointer is of type signed char, and it is being promoted to a signed int while being passed to printf. Thus, the sign bit propagates. Later on, you print it out with %x which means unsigned int in hex, which causes you to print all the 1's (as opposed to correctly interpret them as a part of a 2's complement signed integer). Also, ffffffd2 is 8 hex digits which means it's a 32bit signed integer.

If you declare fileinrampointer as unsigned char or unsigned __int8 the sign bit doesn't propagate during promotion. You may as well leave it signed and cast it

printf("%x\n", static_cast<unsigned char>(*fileinrampointer) );

ISO/IEC 9899:1999 6.5.2.2:

6 . If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. [...]
[...]
7. If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type. The ellipsis notation in a function prototype declarator causes argument type conversion to stop after last declared parameter. The default argument promotions are performed on trailing arguments.

This clearly backs up my statement that this is integer promotion, and not printf interpretation.

Also see
ISO/IEC 9899:1999 7.15.1.1
glibc manual A.2.2.4
glibc manual 12.12.4
securecoding.cert.org

Adrian Panasiuk
It may be helpful to be specific about why the char is being promoted to an int. :)
Greg D
It's not promotion, it's _interpretation_ as int (and rendered as hex) by the printf internals, due to the "%x" format specifier
xtofl
Thanks, I understand why it's happening now.
Columbo
The three most significant bytes are all set to 0xFF before printf gets called, which means it's being promoted to int. That's why the output doesn't cointain garbage but 'ff'.
Adrian Panasiuk