Converting 4 chars to a unsigned long?

C and PASCAL (or any other high-level languages) in here please

Moderators: exxos, simonsunnyboy, Mug UK, Zorro 2, Moderator Team

User avatar
TheNameOfTheGame
Atari God
Atari God
Posts: 1044
Joined: Mon Jul 23, 2012 8:57 pm
Location: Almost Heaven, West Virginia

Converting 4 chars to a unsigned long?

Postby TheNameOfTheGame » Sun Oct 15, 2017 12:43 am

I am trying to read the program header and get the length for the code section.

I can open the file and read the 4 bytes in ok, but when I try to calculate ph_tlen I get a wild number. Can someone point out my error?

Code: Select all

               unsigned long ph_tlen;
               unsigned char read_buf[4];

               Fread( file_handle, 4, read_buf );

               ****** This prints out the correct values ******
               printf("\nrb0 %d rb1 %d rb2 %d rb3 %d", read_buf[0], read_buf[1], read_buf[2], read_buf[3]);

               ****** Here is where I am trying to convert the 4 bytes into a unsigned long ******
               ph_tlen = (read_buf[0] << 24) | (read_buf[1] << 16) | (read_buf[2] << 8) | read_buf[3];

               ****** This prints out an inaccurate number ******
               printf(" tlen %lu", ph_tlen);


User avatar
TheNameOfTheGame
Atari God
Atari God
Posts: 1044
Joined: Mon Jul 23, 2012 8:57 pm
Location: Almost Heaven, West Virginia

Re: Converting 4 chars to a unsigned long?

Postby TheNameOfTheGame » Sun Oct 15, 2017 1:25 am

Eh, figured it out after all. :lol:

Had to change:

Code: Select all

ph_tlen = (read_buf[0] << 24) | (read_buf[1] << 16) | (read_buf[2] << 8) | read_buf[3];


To:

Code: Select all

ph_tlen = ((unsigned long) read_buf[0] << 24) | ((unsigned long ) read_buf[1] << 16) | ((unsigned long ) read_buf[2] << 8) | ((unsigned long) read_buf[3];


I thought since ph_tlen was an unsigned long and read_buf was unsigned char, PureC would convert the unsigned chars to unsigned long during the operation.

I guess not. Don't really understand why it works that way. :?: :?:

mikro
Atari God
Atari God
Posts: 1286
Joined: Sat Sep 10, 2005 11:11 am
Location: Brisbane, Queensland, Australia
Contact:

Re: Converting 4 chars to a unsigned long?

Postby mikro » Sun Oct 15, 2017 2:21 am

No need to do that as complex as that. What about:

Code: Select all

unsigned long ph_tlen;
Fread( file_handle, sizeof(ph_tlen), &ph_tlen );

User avatar
TheNameOfTheGame
Atari God
Atari God
Posts: 1044
Joined: Mon Jul 23, 2012 8:57 pm
Location: Almost Heaven, West Virginia

Re: Converting 4 chars to a unsigned long?

Postby TheNameOfTheGame » Sun Oct 15, 2017 2:57 am

mikro wrote:No need to do that as complex as that. What about:

Code: Select all

unsigned long ph_tlen;
Fread( file_handle, sizeof(ph_tlen), &ph_tlen );


Wow, thanks. :cheers:

I had no idea that would work. I love C, there are so many ways to do the same thing. Of course I'm trying to find the most efficient. Much appreciated!

User avatar
mfro
Atari Super Hero
Atari Super Hero
Posts: 676
Joined: Thu Aug 02, 2012 10:33 am
Location: SW Germany

Re: Converting 4 chars to a unsigned long?

Postby mfro » Sun Oct 15, 2017 6:00 am

As to why this didn't work:
TheNameOfTheGame wrote:

Code: Select all

ph_tlen = (read_buf[0] << 24) | (read_buf[1] << 16) | (read_buf[2] << 8) | read_buf[3];



This is one of the trickier parts of C you need to get used to. What you got fooled by is called integral promotion. In C, all arithmetic operations on types smaller than int are enforced to be calculated on integer types only. Whenever you do a calculation on a char value, that value first gets implicitly converted to a signed integer before evaluation. So, in your first example, read_buf[x] is neither an unsigned char nor an unsigned long, but a signed int. Finally, the end result is truncated to the target type. That's why you suddenly had signed types in between while the original type was unsigned. Read more about this here. Note that gcc, for example, would have emitted a (cryptic, on first sight, but correct if you know the rules) warning that you shifted wider than the int type would allow.

User avatar
charles
10 GOTO 10
10 GOTO 10
Posts: 2031
Joined: Tue Aug 17, 2004 12:11 am
Location: ont. Canada
Contact:

Re: Converting 4 chars to a unsigned long?

Postby charles » Sun Oct 15, 2017 11:11 am

does c have a cvl command?
atari is my lifestyle,not a hobby.
HOLD ON ! ! !,
Im printing unreadable characters ...!

User avatar
charles
10 GOTO 10
10 GOTO 10
Posts: 2031
Joined: Tue Aug 17, 2004 12:11 am
Location: ont. Canada
Contact:

Re: Converting 4 chars to a unsigned long?

Postby charles » Sun Oct 15, 2017 11:14 am

or
bmove
the four bytes to the address of variable ph_tlen?

I have no experience in 'c' language however
just thinking what basic permits
atari is my lifestyle,not a hobby.
HOLD ON ! ! !,
Im printing unreadable characters ...!

User avatar
TheNameOfTheGame
Atari God
Atari God
Posts: 1044
Joined: Mon Jul 23, 2012 8:57 pm
Location: Almost Heaven, West Virginia

Re: Converting 4 chars to a unsigned long?

Postby TheNameOfTheGame » Sun Oct 15, 2017 12:26 pm

mfro wrote:As to why this didn't work:
TheNameOfTheGame wrote:

Code: Select all

ph_tlen = (read_buf[0] << 24) | (read_buf[1] << 16) | (read_buf[2] << 8) | read_buf[3];



This is one of the trickier parts of C you need to get used to. What you got fooled by is called integral promotion. In C, all arithmetic operations on types smaller than int are enforced to be calculated on integer types only. Whenever you do a calculation on a char value, that value first gets implicitly converted to a signed integer before evaluation. So, in your first example, read_buf[x] is neither an unsigned char nor an unsigned long, but a signed int. Finally, the end result is truncated to the target type. That's why you suddenly had signed types in between while the original type was unsigned. Read more about this here. Note that gcc, for example, would have emitted a (cryptic, on first sight, but correct if you know the rules) warning that you shifted wider than the int type would allow.


Thanks for the explanation!

I could see what was happening, but didn't realize why. I was thinking it would use the type of the Lvalue destination for promotion.

Now I know better. :cheers:

mikro
Atari God
Atari God
Posts: 1286
Joined: Sat Sep 10, 2005 11:11 am
Location: Brisbane, Queensland, Australia
Contact:

Re: Converting 4 chars to a unsigned long?

Postby mikro » Sun Oct 15, 2017 10:37 pm

Don't worry, many, many great programmers (and me :D) do this kind of mistake from time to time. I haven't looked deeper as of why there isn't a preceding rule like "if it's unsigned, stay unsigned no matter what" but I'm pretty sure wise men and women from the C committee had their reasons. :-P

User avatar
wongck
Ultimate Atarian
Ultimate Atarian
Posts: 11976
Joined: Sat May 03, 2008 2:09 pm
Location: Far East
Contact:

Re: Converting 4 chars to a unsigned long?

Postby wongck » Sun Oct 15, 2017 11:40 pm

C is very flexible, you can make your 4 bytes into long, short, char or a new type with 3 bytes in size.
Just that you need to know what you are doing.... and that's the pit fall as well ( :wink: you thought you know what you are doing).
My Stuff: FB/Falcon CT63+CTPCI_ATI_RTL8139 14+512MB 30GB HDD CF HxC_SD/ TT030 68882 4+32MB 520MB Nova/ 520STFM 4MB Tos206 SCSI
Shared SCSI Bus:ScsiLink ethernet, 9GB HDD,SD-reader @ http://phsw.atari.org
My Atari stuff for sale - click here for list


Social Media

     

Return to “C / PASCAL etc.”

Who is online

Users browsing this forum: No registered users and 1 guest