Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Is this code valid

1 view
Skip to first unread message

Arin Chaudhuri

unread,
May 27, 2004, 6:37:01 PM5/27/04
to
Hi,
Is the code below that gives the bytes that make up a double valid?
/******/
#include <stdio.h>

int
main(void)
{
double w=0.1;
unsigned char *p;
unsigned char c;
size_t i;
p=(unsigned char *)&w;
for(i=0;i < sizeof w;i++,p++)
{
c=*p;
printf("%X ",(unsigned) c);
}
getchar();
return 0;
}
/****/

My questions are:
1. Is it permissible to cast a pointer to a double to a pointer to an
unsigned char and extract the values byte by byte as above?

2. At the end of the loop p points to a possibly invalid location. I
know that one can point to one past the end of an array, but here this
doesn't hold. Does this lead to undefined behavior?

Martin Dickopp

unread,
May 27, 2004, 7:09:36 PM5/27/04
to
arin_chau...@yahoo.com (Arin Chaudhuri) writes:

> Hi,
> Is the code below that gives the bytes that make up a double valid?
> /******/
> #include <stdio.h>
>
> int
> main(void)
> {
> double w=0.1;
> unsigned char *p;
> unsigned char c;
> size_t i;
> p=(unsigned char *)&w;
> for(i=0;i < sizeof w;i++,p++)
> {
> c=*p;
> printf("%X ",(unsigned) c);
> }
> getchar();
> return 0;
> }
> /****/
>
> My questions are:
> 1. Is it permissible to cast a pointer to a double to a pointer to an
> unsigned char and extract the values byte by byte as above?

Yes. This is know as accessing the "representation" of an object.

> 2. At the end of the loop p points to a possibly invalid location. I
> know that one can point to one past the end of an array, but here this
> doesn't hold. Does this lead to undefined behavior?

No. For the purpose of arithmentic operations on pointers, a pointer to
an object which is not array element behaves like a pointer to an array
of size one. After the loop, `p' points to `&w + 1', i.e. one past what
would be the last element of `w' if it were an array. That's allowed.

Martin


--
,--. Martin Dickopp, Dresden, Germany ,= ,-_-. =.
/ ,- ) http://www.zero-based.org/ ((_/)o o(\_))
\ `-' `-'(. .)`-'
`-. Debian, a variant of the GNU operating system. \_/

Leor Zolman

unread,
May 27, 2004, 7:53:23 PM5/27/04
to
On Fri, 28 May 2004 01:09:36 +0200, Martin Dickopp
<expires-2...@zero-based.org> wrote:

>> 2. At the end of the loop p points to a possibly invalid location. I
>> know that one can point to one past the end of an array, but here this
>> doesn't hold. Does this lead to undefined behavior?
>
>No. For the purpose of arithmentic operations on pointers, a pointer to
>an object which is not array element behaves like a pointer to an array
>of size one. After the loop, `p' points to `&w + 1', i.e. one past what
>would be the last element of `w' if it were an array. That's allowed.

I understand what you mean, and the OP probably does too, but it seems to
me that it would help this explanation a little to explicitly say "pointer
to an array of char of size one" rather than simply "pointer to an array of
size one". Because, as per conventional pointer arithmetic rules, your
later example expression "&w + 1" would mean something totally different
(than what I think you intended) if based on w's actual type.
-leor

>
>Martin

--
Leor Zolman --- BD Software --- www.bdsoft.com
On-Site Training in C/C++, Java, Perl and Unix
C++ users: download BD Software's free STL Error Message Decryptor at:
www.bdsoft.com/tools/stlfilt.html

Barry Schwarz

unread,
May 27, 2004, 11:18:21 PM5/27/04
to
On Thu, 27 May 2004 19:53:23 -0400, Leor Zolman <le...@bdsoft.com>
wrote:

>On Fri, 28 May 2004 01:09:36 +0200, Martin Dickopp
><expires-2...@zero-based.org> wrote:
>
>>> 2. At the end of the loop p points to a possibly invalid location. I
>>> know that one can point to one past the end of an array, but here this
>>> doesn't hold. Does this lead to undefined behavior?
>>
>>No. For the purpose of arithmentic operations on pointers, a pointer to
>>an object which is not array element behaves like a pointer to an array
>>of size one. After the loop, `p' points to `&w + 1', i.e. one past what
>>would be the last element of `w' if it were an array. That's allowed.
>
>I understand what you mean, and the OP probably does too, but it seems to
>me that it would help this explanation a little to explicitly say "pointer
>to an array of char of size one" rather than simply "pointer to an array of
>size one". Because, as per conventional pointer arithmetic rules, your
>later example expression "&w + 1" would mean something totally different
>(than what I think you intended) if based on w's actual type.

But in this case, p points to an array of 1 double and at the end of
the loop points one byte past the last byte in the double.


<<Remove the del for email>>

Leor Zolman

unread,
May 27, 2004, 11:50:11 PM5/27/04
to

Arghhh. For some bizarre reason, the picture in my head of &w had the
pointer pointing to the end of w instead of the beginning. That was new.
Thanks,
-leor

>
>
><<Remove the del for email>>

--

Mike Wahler

unread,
May 28, 2004, 12:42:30 AM5/28/04
to
"Leor Zolman" <le...@bdsoft.com> wrote in message
news:sfddb0pof42a4b9v1...@4ax.com...

> On 28 May 2004 03:18:21 GMT, Barry Schwarz <schw...@deloz.net> wrote:
> >But in this case, p points to an array of 1 double and at the end of
> >the loop points one byte past the last byte in the double.
>
> Arghhh. For some bizarre reason, the picture in my head of &w had the
> pointer pointing to the end of w instead of the beginning. That was new.

No, 'new' would be C++.

Sorry, couldn't resist. :-)

-Mike


E. Robert Tisdale

unread,
May 28, 2004, 1:53:25 AM5/28/04
to
Arin Chaudhuri wrote:

> Is the code below that gives the bytes that make up a double valid?
>
> /******/
> #include <stdio.h>

#include <stdlib.h>
>
> int
> main(int argc, char* argv[]) {
> const double w = 0.1;
> const unsigned char* p = (unsigned char*)(&w);
> for (size_t i = 0; i < sizeof w; ++i) {
> fprintf(stdout, "%X ", (unsigned int)(p[i]));
> }
> getchar();
> return EXIT_SUCCESS;
> }
> /****/
>
> My questions are:

> 1. Is it permissible to cast a pointer to a double
> to a pointer to an unsigned char
> and extract the values byte by byte as above?

That's the way that I'd do it.

> 2. At the end of the loop p points to a possibly invalid location.
> I know that one can point to one past the end of an array,
> but here this doesn't hold. Does this lead to undefined behavior?

No.

Notice that I've trimmed your little program
and made it a little easier to read and understand.

> gcc -Wall -std=c99 -pedantic -o main main.c
> ./main
9A 99 99 99 99 99 B9 3F

Vittal

unread,
May 28, 2004, 2:23:52 AM5/28/04
to
I think the code is valid but it is not portable. It's a typical case
of byte swapping and you see different results on Solaris and Linux
boxes.

Here are my results on solaris and linux:

solaris: 3F B9 99 99 99 99 99 9A
linux: 9A 99 99 99 99 99 B9 3F

if you are running your code on a single platform and not worrying
about taking it to other platforms then you can carry on with you
code.

hope this helps you
-vittal

arin_chau...@yahoo.com (Arin Chaudhuri) wrote in message news:<1f0e1535.0405...@posting.google.com>...

Martin Dickopp

unread,
May 28, 2004, 3:17:26 AM5/28/04
to
Leor Zolman <le...@bdsoft.com> writes:

> On Fri, 28 May 2004 01:09:36 +0200, Martin Dickopp
> <expires-2...@zero-based.org> wrote:
>
>>> 2. At the end of the loop p points to a possibly invalid location. I
>>> know that one can point to one past the end of an array, but here this
>>> doesn't hold. Does this lead to undefined behavior?
>>
>>No. For the purpose of arithmentic operations on pointers, a pointer to
>>an object which is not array element behaves like a pointer to an array
>>of size one. After the loop, `p' points to `&w + 1', i.e. one past what
>>would be the last element of `w' if it were an array. That's allowed.
>
> I understand what you mean, and the OP probably does too, but it seems to
> me that it would help this explanation a little to explicitly say "pointer
> to an array of char of size one" rather than simply "pointer to an array of
> size one".

That's /not/ what I mean. If that's what you understood, my explanation
wasn't good enough.

> Because, as per conventional pointer arithmetic rules, your later
> example expression "&w + 1" would mean something totally different
> (than what I think you intended) if based on w's actual type.

This is the actual standard text in 6.5.6#7:

| For the purposes of these operators, a pointer to an object that is
| not an element of an array behaves the same as a pointer to the first
| element of an array of length one with the type of the object as its
| element type.

`w' has type `double'. Once a pointer has been set to `&w', arithmetic
operations (only those allowed for pointers, of course) can used to make
the pointer point to any address between `&w' and `&w + 1' (inclusively),
which are more than two addresses unless `sizeof (double) == 1'.

`p' was a pointer to `unsigned char', but that doesn't matter, because
it's not the type of the pointer, but the type of the underlying object
that is used to determine the valid address range.

Clarification for the OP: I assume you know the following fact, but
just in case you don't, I'll mention it anyway. Arithmetic on pointers
works in units of the size of the type pointed to, i.e. if `w' has type
`double', `&w + 1' points to the same address as `(unsigned char *)&w +
sizeof (double)'.

Dan Pop

unread,
May 28, 2004, 7:10:51 AM5/28/04
to

>Is the code below that gives the bytes that make up a double valid?
>/******/
>#include <stdio.h>
>
>int
>main(void)
>{
> double w=0.1;
> unsigned char *p;
> unsigned char c;
> size_t i;
> p=(unsigned char *)&w;
> for(i=0;i < sizeof w;i++,p++)
> {
> c=*p;
> printf("%X ",(unsigned) c);
> }
> getchar();
> return 0;
>}
>/****/

Not only is it valid, but it looks as if it were written by someone
reading c.l.c on a regular basis:

1. c is correctly declared as unsigned char and p as pointer to unsigned
char.

2. i is declared as size_t, to keep even the most anal crititcs happy.

3. c is cast to unsigned in the printf call, to match the type expected
by %X.

The only missing bit is a newline to stdout before returning from main().
No, the getchar() call is not an appropriate replacement for that.

OTOH, the code contains a lot of redundancy, as if it were written by
someone still unfamiliar with writing C code. If I were to write it
myself, it would look like this:

#include <stdio.h>

int main(void)
{
double w = 0.1;

unsigned char *p = (unsigned char *)&w;
size_t i;

for (i = 0; i < sizeof w; i++) printf("%02X ", (unsigned)p[i]);
printf("\n");
return 0;
}

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Dan...@ifh.de

Dan Pop

unread,
May 28, 2004, 7:17:56 AM5/28/04
to

>I think the code is valid but it is not portable.

Any program displaying the representation of a value is, *by definition*,
not strictly conforming. Whether it is portable or not depends on your
definition of "portability". According to the most common definition
"it does the job it was supposed to, on any conforming implementation",
it *is* portable (modulo the missing newline bit) as it does exactly what
it is supposed to: display the representation of a double value. It is
the representation of a double value that is not portable, but this is not
the program's fault.

"Dario (drinking coffee in the office…)"

unread,
May 28, 2004, 7:45:05 AM5/28/04
to
Dan Pop wrote:

> The only missing bit is a newline to stdout before returning from main().

Eh????
The standard require this?
Can you cite verb and phrase please?

Reading myself the standard I found something like:

If the main function returns to its original caller,
or if the exit function is called, all open files are
closed (hence all output streams are flushed) before
program termination.

So I think there is no reason
to write "\n" before returning from main()..

- Dario

Leor Zolman

unread,
May 28, 2004, 8:07:40 AM5/28/04
to

You may want to go read the "Program output" thread that began on 5/24.
This isn't as simple an issue as it might seem.
-leor

Martin Dickopp

unread,
May 28, 2004, 8:18:23 AM5/28/04
to
"Dario (drinking coffee in the office…)" <da...@despammed.com> writes:

> Dan Pop wrote:
>
>> The only missing bit is a newline to stdout before returning from main().
>
> Eh????
> The standard require this?
> Can you cite verb and phrase please?

This has just been discussed in great detail in another thread in this
newsgroup. 7.19.2#2:

| A text stream is an ordered sequence of characters composed into
| lines, each line consisting of zero or more characters plus a
| terminating new-line character. Whether the last line requires a
| terminating new-line character is implementation-defined.

> Reading myself the standard I found something like:
>
> If the main function returns to its original caller,
> or if the exit function is called, all open files are
> closed (hence all output streams are flushed) before
> program termination.

There is no doubt that the stdout stream is closed (and therefore
flushed), however this:

> [...] there is no reason to write "\n" before returning from main()..

does not follow from the fact that stdout is flushed.

"Dario (drinking coffee in the office…)"

unread,
May 28, 2004, 8:42:08 AM5/28/04
to
So, if I understood correctly the problem:
-1- The standard does not require a final "\n".
-2- A specific implementation may (or may not) require a final "\n".
-2.a- If a specific implementation require a final "\n" _and_
I miss the final "\n" then everything may happen.
But in any case the file is correctly closed and flushed
(because I leave the main function).
So everything may happen but _only_ _after_ my program
is terminated.

Is this right?

- Dario

j0mbolar

unread,
May 28, 2004, 9:56:15 AM5/28/04
to
arin_chau...@yahoo.com (Arin Chaudhuri) wrote in message news:<1f0e1535.0405...@posting.google.com>...
> Hi,
> Is the code below that gives the bytes that make up a double valid?
> /******/
> #include <stdio.h>
>
> int
> main(void)
> {
> double w=0.1;
> unsigned char *p;
> unsigned char c;
> size_t i;
> p=(unsigned char *)&w;
> for(i=0;i < sizeof w;i++,p++)
> {
> c=*p;
> printf("%X ",(unsigned) c);
> }
> getchar();
> return 0;
> }
> /****/
>
> My questions are:
> 1. Is it permissible to cast a pointer to a double to a pointer to an
> unsigned char and extract the values byte by byte as above?
>

I don't believe a pointer to double will be correctly
aligned for a pointer to unsigned char.

> 2. At the end of the loop p points to a possibly invalid location. I
> know that one can point to one past the end of an array, but here this
> doesn't hold. Does this lead to undefined behavior?

no. what would lead to undefined behavior is if you used
it in an l-value expression.

Martin Dickopp

unread,
May 28, 2004, 9:55:54 AM5/28/04
to
"Dario (drinking coffee in the office…)" <da...@despammed.com> writes:

> So, if I understood correctly the problem:
> -1- The standard does not require a final "\n".

A program is only strictly conforming if it writes a terminating
new-line character to every text output stream it has written to.
If it doesn't, it relies on implementation-defined behavior.

> -2- A specific implementation may (or may not) require a final "\n".

Yes.

> -2.a- If a specific implementation require a final "\n" _and_
> I miss the final "\n" then everything may happen.

Yes.

> But in any case the file is correctly closed and flushed
> (because I leave the main function).

No. "Everything may happen" means that, well, /everything/ may
happen. :) /Not/ flushing and closing the stream is certainly a
behavior contained in "everything".

My previous post might have been misleading. The guarantee that the
stdout stream is flushed and closed is only valid if no undefined
behavior is invoked. As soon as undefined behavior is invoked, there
are no more guarantees at all.

> So everything may happen but _only_ _after_ my program
> is terminated.

The behavior becomes undefined when the stream is closed, which is
before the program terminates.

Martin Dickopp

unread,
May 28, 2004, 10:12:03 AM5/28/04
to
j0mb...@engineer.com (j0mbolar) writes:

> arin_chau...@yahoo.com (Arin Chaudhuri) wrote in message news:<1f0e1535.0405...@posting.google.com>...
>> Hi,
>> Is the code below that gives the bytes that make up a double valid?
>> /******/
>> #include <stdio.h>
>>
>> int
>> main(void)
>> {
>> double w=0.1;
>> unsigned char *p;
>> unsigned char c;
>> size_t i;
>> p=(unsigned char *)&w;
>> for(i=0;i < sizeof w;i++,p++)
>> {
>> c=*p;
>> printf("%X ",(unsigned) c);
>> }
>> getchar();
>> return 0;
>> }
>> /****/
>>
>> My questions are:
>> 1. Is it permissible to cast a pointer to a double to a pointer to an
>> unsigned char and extract the values byte by byte as above?
>
> I don't believe a pointer to double will be correctly aligned
> for a pointer to unsigned char.

Since `unsigned char' has a size of one byte, a pointer to `unsigned
char' cannot have any other alignment requirement than one byte.

Arin Chaudhuri

unread,
May 28, 2004, 12:21:09 PM5/28/04
to
Vittal wrote:

> I think the code is valid but it is not portable. It's a typical case
> of byte swapping and you see different results on Solaris and Linux
> boxes.
>

I am sorry I don't understand you at all. If the representation of
double is different, the answers should be different. Is writing a
portable program(as you mean it) possible?

Eric Sosman

unread,
May 28, 2004, 12:43:29 PM5/28/04
to
j0mbolar wrote:
> arin_chau...@yahoo.com (Arin Chaudhuri) wrote in message news:<1f0e1535.0405...@posting.google.com>...
>>
>>My questions are:
>>1. Is it permissible to cast a pointer to a double to a pointer to an
>>unsigned char and extract the values byte by byte as above?
>>
> I don't believe a pointer to double will be correctly
> aligned for a pointer to unsigned char.

The alignment requirement for any type T must be a
divisor of sizeof(T). (Proof: In `T array[2];' both
`array[0]' and `array[1]' must be correctly aligned.)
Since `sizeof(unsigned char)' is divisible only by one
and since one is a divisor of every type's size, every
type is suitably aligned for `unsigned char'.

>>2. At the end of the loop p points to a possibly invalid location. I
>>know that one can point to one past the end of an array, but here this
>>doesn't hold. Does this lead to undefined behavior?
>
> no. what would lead to undefined behavior is if you used
> it in an l-value expression.

Not clear what you mean by "it." It's certainly all
right to use `p' itself as an lvalue: Apply `--' to it,
for example, and it once again points to a known-to-exist
byte. What you mustn't do is `*p' or equivalent while
`p' points past the end of the object. It doesn't matter
whether this `*p' is the l.h.s. of an assignment, or just
a read-only operand elsewhere in an expression; it's
U.B. as soon as you evaluate `*p'.

--
Eric....@sun.com

Emmanuel Delahaye

unread,
May 28, 2004, 2:04:26 PM5/28/04
to
In 'comp.lang.c', vsnad...@yahoo.com (Vittal) wrote:

> I think the code is valid but it is not portable. It's a typical case
> of byte swapping and you see different results on Solaris and Linux
> boxes.
>
> Here are my results on solaris and linux:
>
> solaris: 3F B9 99 99 99 99 99 9A
> linux: 9A 99 99 99 99 99 B9 3F
>
> if you are running your code on a single platform and not worrying
> about taking it to other platforms then you can carry on with you
> code.

The code *is* portable. The result is not.

--
-ed- get my email here: http://marreduspam.com/ad672570
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?lib=c99
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Dik T. Winter

unread,
May 28, 2004, 9:25:12 PM5/28/04
to
In article <2d31a9f9.04052...@posting.google.com> j0mb...@engineer.com (j0mbolar) writes:
> arin_chau...@yahoo.com (Arin Chaudhuri) wrote in message news:<1f0e1535.0405...@posting.google.com>...
> > My questions are:
> > 1. Is it permissible to cast a pointer to a double to a pointer to an
> > unsigned char and extract the values byte by byte as above?
>
> I don't believe a pointer to double will be correctly
> aligned for a pointer to unsigned char.

You may believe so, but you are wrong.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

Orhan Kavrakoglu

unread,
May 30, 2004, 9:40:39 AM5/30/04
to
On 28 May 2004 11:10:51 GMT, Dan...@cern.ch (Dan Pop) wrote:

>In <1f0e1535.0405...@posting.google.com> arin_chau...@yahoo.com (Arin Chaudhuri) writes:
>
>>Is the code below that gives the bytes that make up a double valid?
>>/******/
>>#include <stdio.h>
>>
>>int
>>main(void)
>>{
>> double w=0.1;
>> unsigned char *p;
>> unsigned char c;
>> size_t i;
>> p=(unsigned char *)&w;
>> for(i=0;i < sizeof w;i++,p++)
>> {
>> c=*p;
>> printf("%X ",(unsigned) c);
>> }
>> getchar();
>> return 0;
>>}
>>/****/
>

[snip]


>3. c is cast to unsigned in the printf call, to match the type expected
> by %X.

Why is this necessary?
--
aib

ISP e-mail accounts are good for receiving spam.

Martin Dickopp

unread,
May 30, 2004, 10:17:06 AM5/30/04
to
Orhan Kavrakoglu <galg...@ttnet.net.tr> writes:

The following text in the standard requires it for a program with
well-defined behavior:

| 7.1.4 Use of library functions
|
| 1 Each of the following statements applies unless explicitly stated
| otherwise in the detailed descriptions that follow: If an argument
| to a function has an invalid value (such as a value outside the
| domain of the function, or a pointer outside the address space of
| the program, or a null pointer, or a pointer to non-modifiable
| storage when the corresponding parameter is not const-qualified) or
| a type (after promotion) not expected by a function with variable
| number of arguments, the behavior is undefined. [...]

Since `c' has type `unsigned char', it is promoted to `int', unless
`int' cannot represent all values of `unsigned char', in which case `c'
is promoted to `unsigned int'. To make the program work correctly on
all implementations (even those which can represent all values of an
`unsigned char' in an `int', which is commonly the case for hosted
implementations), the cast is therefore necessary.

Vittal

unread,
Jun 2, 2004, 6:05:59 AM6/2/04
to
Thanks for your correction.. Btw,I meant results will be different on
different machine...hence said not portable

Dan...@cern.ch (Dan Pop) wrote in message news:<c97754$imn$5...@sunnews.cern.ch>...

0 new messages