Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Re: A portable code to create a 4-bytes Big Endian twos complement

Reply
Thread Tools

Re: A portable code to create a 4-bytes Big Endian twos complement

 
 
Spiros Bousbouras
Guest
Posts: n/a
 
      03-17-2011
On Thu, 17 Mar 2011 19:25:40 +0100
pozz <(E-Mail Removed)> wrote:
> Il 17/03/2011 18:16, pozz ha scritto:
> > On pag. 179 of "C Unleashed" book (by Heathfield, Kirby et al.), there
> > is this code for a similar task (ifp is an input stream):
> > [...]

>
> And another thing I couldn't understand on that book, for a similar topic.
>
> On pag. 178 it explains how to write and read a two-bytes integer value
> on a portable data file (writing/reading to a file is a similar task to
> sending/receiving to/from a network).


[...]

> How is possible the book is wrong?


Books can have mistakes. But in this case I don't know if it has made a
mistake because I don't know what "two-bytes integer value" means.
Could you provide a precise definition ?

> If I want to fix this, how can I do?


Exactly what do you want to achieve ?
 
Reply With Quote
 
 
 
 
Spiros Bousbouras
Guest
Posts: n/a
 
      03-17-2011
On Thu, 17 Mar 2011 21:03:19 +0100
pozz <(E-Mail Removed)> wrote:
> Il 17/03/2011 19:43, Spiros Bousbouras ha scritto:
> > Books can have mistakes. But in this case I don't know if it has made a
> > mistake because I don't know what "two-bytes integer value" means.
> > Could you provide a precise definition ?

>
> The book was talking about the issue to store an integer value on a file
> in a portable way.
> "Suppose we decide that the int as represented in the data file will be
> two bytes in little-endian order [...]".
> After the writing (putc) instructions, the author says:
> "Key point number two is that we're not concerned with how big an int
> happens to be on this machine; [...]"
>
> So I think that the author has presented a code that works on every C
> implementation (16-, 32-, 64-bits sized int).


I don't have the book but I don't think that 32 or 64 bits sized int is
meant to count as 2 bytes. My guess is that when it says 2 bytes it
means that the whole bit pattern which represents the number is stored
in 2 bytes.
 
Reply With Quote
 
 
 
 
Ben Bacarisse
Guest
Posts: n/a
 
      03-18-2011
pozz <(E-Mail Removed)> writes:

> Il 17/03/2011 21:15, Spiros Bousbouras ha scritto:
>>> So I think that the author has presented a code that works on every C
>>> implementation (16-, 32-, 64-bits sized int).

>>
>> I don't have the book but I don't think that 32 or 64 bits sized int is
>> meant to count as 2 bytes. My guess is that when it says 2 bytes it
>> means that the whole bit pattern which represents the number is stored
>> in 2 bytes.

>
> The size of int variable in memory depends on implementation (16, 32
> or 64 bits or maybe other values), but the value stored in the file is
> fixed arbitrarily to 2-bytes little-endian.
> So the author proposes the code:
> putc(i & 0xff, ofp);
> putc((i >> & 0xff, ofp);
> Indeed, i (an int variable) could be 16, 32 or 64 bits, but the 2
> bytes written to ofp will be always the same (of course, the value of
> i must be between -32767 and +32767).
>
> For example, suppose i contains the value 600. It could be represented
> in memory as:
> 0258 (16-bits big-endian)
> 00000258 (32-bits big-endian)
> 5802 (16-bits little-endian)
> 58020000 (32-bits little-endian)
> With the above two lines of code, I'll write always the same two bytes
> on the file ofp: 0x58 (the first) and 0x02 (the second).
>
> Now I want to write a function that returns the same value in a int
> variable, starting from 0x58 and 0x02 bytes read from the file. The
> code should be portable on 16-, 32- and maybe 64-bits int
> implementations.
> And the value stored in the file could be negative.
>
> The goal of this will be to have a code that writes and reads a
> *portable data file*, so a file that can be created by an application
> on a machine and read by another application on another machine.
> Or a data packet sent from an application running on a machine and
> received by an application running on a different machine.


If you can, avoid using signed binary numbers as a portable
representation but if you can't you can read the two bytes and pack
them into an unsigned int:

int a = fgetc(fp);
int b = fgetc(fp);
unsigned int ux = (((unsigned)b) << | a;

(obviously check for EOF and errors in the real code). Then you need to
convert this to an int. One portable way is like this:

int x;
if (ux >= 0x8000u) {
x = 0xffffu - ux;
x = -x - 1;
}
else x = ux; /* conversion is in range possible */

This came up here some time ago (July 2010) and Tim Rentsch came up
with:

(int)(ux & 32767) - (int)(ux/2 & 16384) - (int)(ux/2 & 16384);

which has several advantages over my suggestion.

--
Ben.
 
Reply With Quote
 
pozz
Guest
Posts: n/a
 
      03-18-2011
On 18 Mar, 03:23, Ben Bacarisse <(E-Mail Removed)> wrote:
> If you can, avoid using signed binary numbers as a portable
> representation


Unfortunately I can't avoid it, because the data packet format
is fixed not by me.


> but if you can't you can read the two bytes and pack
> them into an unsigned int:


So you agree with me that the two reading instructions can't work with
signed values on 32 bits machines.

I found the same code on Question 12.42 of comp.lang.c FAQ ("How can I
write code to conform to these old, binary data file formats?"). There
the following struct is defined:
struct mystruct {
char c;
long int i32;
int i16;
} s;
and the following code is used to read the 16 bits value:
s.i16 = getc(fp) << 8;
s.i16 |= getc(fp);

If we assume the values stored in the file are unsigned (0-65535), the
member i16 should had be defined as unsigned int (not signed int),
otherwise the value 40000 can't be correctly received on 16-bits
machines.

If we assume the values stored in the file are signed (-32767 -
+32767), the code to read them doesn't work for negative values on
implementations with int size greater than 16 bits (the value -1 is
written in the file as 0xFF 0xFF, but is read back as 65535 on 32-bits
platforms).

In both cases, the code doesn't work and should be fixed.


> * int a = fgetc(fp);
> * int b = fgetc(fp);
> * unsigned int ux = (((unsigned)b) << | a;
>[...]
> * int x;
> * if (ux >= 0x8000u) {
> * * * x = 0xffffu - ux;
> * * * x = -x - 1;
> * }
> * else x = ux; /* conversion is in range possible */


Ok, it could be a solution. Another solution would be (if I assume the
presence of int16_t):
int i = (int16_t)(((unsigned)b) << | a;


> This came up here some time ago (July 2010) and Tim Rentsch came up
> with:
>
> * (int)(ux & 32767) - (int)(ux/2 & 16384) - (int)(ux/2 & 16384);
>
> which has several advantages over my suggestion.


I found the _very long_ thread. I'll try to understand it alone, but
it seems difficult for my small knowledge of C language.
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      03-18-2011
pozz <(E-Mail Removed)> writes:

> On 18 Mar, 03:23, Ben Bacarisse <(E-Mail Removed)> wrote:
>> [...] you can read the two bytes and pack
>> them into an unsigned int:

>
> So you agree with me that the two reading instructions can't work with
> signed values on 32 bits machines.


I am not exactly sure what you think I am agreeing with. You showed
code that looked wrong but without context it's hard to know what the
code was supposed to do. For example, this:

> I found the same code on Question 12.42 of comp.lang.c FAQ ("How can I
> write code to conform to these old, binary data file formats?"). There
> the following struct is defined:
> struct mystruct {
> char c;
> long int i32;
> int i16;
> } s;
> and the following code is used to read the 16 bits value:
> s.i16 = getc(fp) << 8;
> s.i16 |= getc(fp);
>
> If we assume the values stored in the file are unsigned (0-65535), the
> member i16 should had be defined as unsigned int (not signed int),
> otherwise the value 40000 can't be correctly received on 16-bits
> machines.


is not as bad as you think since the context makes it clear that the
purpose is to read signed 16-bit ints. 40000 is not an option.

> If we assume the values stored in the file are signed (-32767 -
> +32767), the code to read them doesn't work for negative values on
> implementations with int size greater than 16 bits (the value -1 is
> written in the file as 0xFF 0xFF, but is read back as 65535 on 32-bits
> platforms).


That's not a good assumption. The context is clear: ints are 16 bits.
I agree that it could be made more explicit, and it should certainly
mention the reliance on an implementation-defined conversion, but the
code is not intended to work with all int sizes. (I think the FAQ dates
from before C99 so there is no possibility of a signal being raised.)

> In both cases, the code doesn't work and should be fixed.


Have you told the people concerned?

>> * int a = fgetc(fp);
>> * int b = fgetc(fp);
>> * unsigned int ux = (((unsigned)b) << | a;
>>[...]
>> * int x;
>> * if (ux >= 0x8000u) {
>> * * * x = 0xffffu - ux;
>> * * * x = -x - 1;
>> * }
>> * else x = ux; /* conversion is in range possible */

>
> Ok, it could be a solution. Another solution would be (if I assume the
> presence of int16_t):
> int i = (int16_t)(((unsigned)b) << | a;


No, that does not address the question -- the implementation-defined
conversion when an unsigned int value it out of range for int. You may
be happy with assuming that it works as you expect, but you seemed to
want a 100% portable solution.

>> This came up here some time ago (July 2010) and Tim Rentsch came up
>> with:
>>
>> * (int)(ux & 32767) - (int)(ux/2 & 16384) - (int)(ux/2 & 16384);
>>
>> which has several advantages over my suggestion.

>
> I found the _very long_ thread. I'll try to understand it alone, but
> it seems difficult for my small knowledge of C language.


If I recall, after solutions were posted a lot of the thread was about
readability and the ability of compilers to optimise the resulting code.

--
Ben.
 
Reply With Quote
 
pozz
Guest
Posts: n/a
 
      03-18-2011
On 18 Mar, 13:43, Ben Bacarisse <(E-Mail Removed)> wrote:
> > I found the same code on Question 12.42 of comp.lang.c FAQ ("How can I
> > write code to conform to these old, binary data file formats?"). There
> > the following struct is defined:
> > * struct mystruct {
> > * * char c;
> > * * long int i32;
> > * * int i16;
> > * } s;
> > and the following code is used to read the 16 bits value:
> > * s.i16 = getc(fp) << 8;
> > * s.i16 |= getc(fp);

>
> > If we assume the values stored in the file are unsigned (0-65535), the
> > member i16 should had be defined as unsigned int (not signed int),
> > otherwise the value 40000 can't be correctly received on 16-bits
> > machines.

>
> is not as bad as you think since the context makes it clear that the
> purpose is to read signed 16-bit ints. *40000 is not an option.


Ok, for me it wasn't so clear...


> > If we assume the values stored in the file are signed (-32767 -
> > +32767), the code to read them doesn't work for negative values on
> > implementations with int size greater than 16 bits (the value -1 is
> > written in the file as 0xFF 0xFF, but is read back as 65535 on 32-bits
> > platforms).

>
> That's not a good assumption. *The context is clear: ints are 16 bits.


Ok, even in this case I made the assumption the code worked also for
32 bits machines.

Anyway you agree with me when I say that the code in the FAQ doesn't
work for 32 bits integers, don't you?


> > Ok, it could be a solution. Another solution would be (if I assume the
> > presence of int16_t):
> > * int i = (int16_t)(((unsigned)b) << | a;

>
> No, that does not address the question -- the implementation-defined
> conversion when an unsigned int value it out of range for int. *You may
> be happy with assuming that it works as you expect, but you seemed to
> want a 100% portable solution.


You are right. Now I understand that unsigned->int conversion is
bad
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      03-18-2011
pozz <(E-Mail Removed)> writes:

> On 18 Mar, 13:43, Ben Bacarisse <(E-Mail Removed)> wrote:
>> > I found the same code on Question 12.42 of comp.lang.c FAQ ("How can I
>> > write code to conform to these old, binary data file formats?"). There
>> > the following struct is defined:
>> > * struct mystruct {
>> > * * char c;
>> > * * long int i32;
>> > * * int i16;
>> > * } s;
>> > and the following code is used to read the 16 bits value:
>> > * s.i16 = getc(fp) << 8;
>> > * s.i16 |= getc(fp);

<snip>
>> > If we assume the values stored in the file are signed (-32767 -
>> > +32767), the code to read them doesn't work for negative values on
>> > implementations with int size greater than 16 bits (the value -1 is
>> > written in the file as 0xFF 0xFF, but is read back as 65535 on 32-bits
>> > platforms).

>>
>> That's not a good assumption. *The context is clear: ints are 16 bits.

>
> Ok, even in this case I made the assumption the code worked also for
> 32 bits machines.
>
> Anyway you agree with me when I say that the code in the FAQ doesn't
> work for 32 bits integers, don't you?


Yes, nor for 18-bit ints or 64 bit ones. The code has a purpose and it
does not do anything else. If your point is "I'd rather the FAQ had an
example of reading a 16-bit signed 2's complement integer into an int of
any permitted size" then I agree that might be more interesting but i
don't think it makes the current code wrong.

<snip>
--
Ben.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: A portable code to create a 4-bytes Big Endian twos complementsigned integer in a misaligned address Jorgen Grahn C Programming 2 03-25-2011 12:43 PM
Re: A portable code to create a 4-bytes Big Endian twos complement signed integer in a misaligned address Tim Rentsch C Programming 0 03-19-2011 04:48 PM
Re: A portable code to create a 4-bytes Big Endian twos complementsigned integer in a misaligned address James Kuyper C Programming 3 03-19-2011 02:19 PM
little endian , big endian , big headache manishster@gmail.com C Programming 5 08-31-2006 12:28 AM
twos complement data redstripe VHDL 3 04-24-2006 01:35 PM



Advertisments