undefined behavior or not undefined behavior? That is the question

  • Thread starter Mantorok Redgormor
  • Start date
M

Mantorok Redgormor

#include <stdio.h>

struct foo { int example; struct bar *ptr; };

int main(void)
{
struct foo baz;
baz.ptr = NULL; /* Undefined behavior? */

return 0;
}


My second question is not related to undefined behavior.
I read that bitwise AND is equivalent to
"Multiplication modulus two" They made some notation
with something that looked like two Zs'

Anyone familiar with that?

However:

printf("%d\n", 10 & 42);

printf("%d\n", (10 * 42) % 2);

most certainly differ.

but they used ^ for AND and said:

a * b (mod 2) = a ^ b
 
P

Papadopoulos Giannis

Mantorok said:
#include <stdio.h>

struct foo { int example; struct bar *ptr; };

int main(void)
{
struct foo baz;
baz.ptr = NULL; /* Undefined behavior? */

return 0;
}

first of all define struct bar nad #include <stdlib.h>

why should assignment of a pointer to NULL should be undefined
My second question is not related to undefined behavior.
I read that bitwise AND is equivalent to
"Multiplication modulus two" They made some notation
with something that looked like two Zs'

I don't think this is right... Am I missing something?
but they used ^ for AND and said:

a * b (mod 2) = a ^ b

the ^ is not AND operator, it is the XOR operator...
and it doesn't seem to work either...

--
#include <stdio.h>
#define p(s) printf(#s" endian")
int main(void){int v=1;*(char*)&v?p(Little):p(Big);return 0;}

Giannis Papadopoulos
http://dop.users.uth.gr/
University of Thessaly
Computer & Communications Engineering dept.
 
A

Arthur J. O'Dwyer

first of all define struct bar nad #include <stdlib.h>

Unnecessary and unnecessary, respectively. A definition for
'struct bar' is not needed in order to declare a pointer to said
among many other places said:
why should assignment of a pointer to NULL should be undefined

Who knows /what/ was running through Mantorok's head? [To
the OP: Why not /tell/ us why you think such-and-such should be
undefined, or defined, rather than just posting a random text
file and letting us run it through a compiler for you? How do
you expect to learn anything this way?]

I don't think this is right... Am I missing something?

Yes, but I have no idea what, because, like the OP, you didn't
give any reasons for your statement that you "don't think this
is right."
Bitwise AND is exactly isomorphic to multiplication in the
field of the integers modulo 2. Compare:

0 & 0 = 0 0 * 0 = 0
0 & 1 = 0 0 * 1 = 0
1 & 0 = 0 1 * 0 = 0
1 & 1 = 1 1 * 1 = 1

See? Same thing.

Do you mean "they" (perhaps a math textbook?) used the
logical AND operator, looking something like an upside-down wide V,
or the exponentiation operator "up-arrow," displayed on a computer
screen as "^"?
In C, logical AND is spelled &&, exponentiation is spelled "pow"
(after #including <math.h>), and the operator spelled ^ is pronounced
"bitwise XOR."

[sig includes]
#include <stdio.h>
#define p(s) printf(#s" endian")
int main(void){int v=1;*(char*)&v?p(Little) : p(Big); return 0;}

Oh yeah, and that code isn't c.l.c-compliant. :) [ISO standard
C doesn't really give any useful definitions regarding endianness,
nor does it guarantee that the attempted evaluation of *(char*)&v
won't invoke undefined behavior on the DeathStation 9000.]

-Arthur
 
P

Papadopoulos Giannis

Arthur said:
Unnecessary and unnecessary, respectively. A definition for
'struct bar' is not needed in order to declare a pointer to said
struct. And NULL is defined in <stdio.h>, among many other places,
AFAIR.

Hmm, whenever I used NULL, I used it with malloc() calls.. So I thought
they were both in stdlib.h...
Yes, but I have no idea what, because, like the OP, you didn't
give any reasons for your statement that you "don't think this
is right."
Bitwise AND is exactly isomorphic to multiplication in the
field of the integers modulo 2. Compare:

0 & 0 = 0 0 * 0 = 0
0 & 1 = 0 0 * 1 = 0
1 & 0 = 0 1 * 0 = 0
1 & 1 = 1 1 * 1 = 1

See? Same thing.

Maybe for 1 and 0 (as integers)... elsewhere is unapplicable...
[sig includes]
#include <stdio.h>
#define p(s) printf(#s" endian")
int main(void){int v=1;*(char*)&v?p(Little) : p(Big); return 0;}


Oh yeah, and that code isn't c.l.c-compliant. :) [ISO standard
C doesn't really give any useful definitions regarding endianness,
nor does it guarantee that the attempted evaluation of *(char*)&v
won't invoke undefined behavior on the DeathStation 9000.]

I am only trying to find if the machine is big endian or little endian..
After 0.29 s in google I found
http://www.treedragon.com/ged/fe/no/endianess.htm

And why should *(char*)&v invoke undefined behaviour? I am only doing this

union {
int v;
char c[4]; /* assuming 32-bit machine */
};

So v in big endian is 0x00 0x00 0x00 0x01 and in little endian is 0x01
0x00 0x00 0x00.

Using c[0] (or equivalently *(char*)&v) one can find endianess.. Still,
this doesn't work on machines with 8-bit integers...


--
#include <stdio.h>
#define p(s) printf(#s" endian")
int main(void){int v=1;*(char*)&v?p(Little):p(Big);return 0;}

Giannis Papadopoulos
http://dop.users.uth.gr/
University of Thessaly
Computer & Communications Engineering dept.
 
M

Malcolm

Papadopoulos Giannis said:
Hmm, whenever I used NULL, I used it with malloc() calls.. So I
thought they were both in stdlib.h...
NULL is defined in lots of headers for convenience.
And why should *(char*)&v invoke undefined behaviour? I am only
doing this
The answer is that there might be trap representations. For instance, a
Communist computer manufacturer could declare the numer 36 to be an illegal
representation. Every time the computer detects it, it could abort with an
error "Capitalist user detected".
union {
int v;
char c[4]; /* assuming 32-bit machine */
};

So v in big endian is 0x00 0x00 0x00 0x01 and in little endian is 0x01
0x00 0x00 0x00.

Using c[0] (or equivalently *(char*)&v) one can find endianess.. Still,
this doesn't work on machines with 8-bit integers...
No you are not. Unions are designed to save space, but there is guarantee
about layout. I don't actually know any trap architectures, but probably the
layout would be as you say, and a trap would result as you illegally access
a char after writing an int.
 
P

pete

Papadopoulos said:
Arthur J. O'Dwyer wrote:
Hmm, whenever I used NULL, I used it with malloc() calls..
So I thought they were both in stdlib.h...

They are both in stdlib.h. All of the macros,
which are needed to describe any standard library function,
are defined in the header corresponding to the function.
Therefore, all standard library headers which have the prototype
for any function capable of returning NULL, define NULL too.
malloc takes a size_t argument,
so you can assume that size_t is defined in stdlib.h, also.
I am only trying to find if the machine is big
endian or little endian..

There's also the possibility of mixed endian.
After 0.29 s in google I found
http://www.treedragon.com/ged/fe/no/endianess.htm

And why should *(char*)&v invoke undefined behaviour?
/* assuming 32-bit machine */
So v in big endian is 0x00 0x00 0x00 0x01 and in little endian is 0x01
0x00 0x00 0x00.

Using c[0] (or equivalently *(char*)&v)
one can find endianess.. Still,
this doesn't work on machines with 8-bit integers...

There are none in C.
type int, has exactly 1 sign bit and at least 15 value bits, always.
#include <stdio.h>
#define p(s) printf(#s" endian")
int main(void){int v=1;*(char*)&v?p(Little):p(Big);return 0;}

We don't generally assume a 32 bit machine, here.
If int has any padding, it's possible that *(char*)&v
might be signed and also a trap representation of negative zero.
 
C

CBFalconer

Papadopoulos said:
first of all define struct bar nad #include <stdlib.h>

Why should he? That is a serious question. He doesn't need
stdio.h either.
 
M

Mantorok Redgormor

Arthur J. O'Dwyer said:
first of all define struct bar nad #include <stdlib.h>

Unnecessary and unnecessary, respectively. A definition for
'struct bar' is not needed in order to declare a pointer to said
among many other places said:
why should assignment of a pointer to NULL should be undefined

Who knows /what/ was running through Mantorok's head? [To
the OP: Why not /tell/ us why you think such-and-such should be
undefined, or defined, rather than just posting a random text
file and letting us run it through a compiler for you? How do
you expect to learn anything this way?]

well if an lvalue does not designate an object
then it invokes undefined behavior.

you need type information for a type to not be
an incomplete type.

until then, the type of something is incomplete and
does not refer to an object, right?

so when you have a struct declaration of:

struct foo { int example; struct bar *ptr; };

and then supply your definition:

struct foo baz;

baz is an actual object, example is an actual object
but what about "ptr" ? it is not a valid pointer object
right?

so it cannot hold:

baz.ptr = NULL; /* can't hold the value of NULL? */

and also under such a circumstance, why is this even
allowed in this regard?

If the type definition is never given for "struct bar"
then the type may never be completed
so in essence you end up with a completely useless
incomplete type in this regard.

it would seem logical for a compiler
to have to issue some type of diagnostic
if it knows the type is never completed.
Yes, but I have no idea what, because, like the OP, you didn't
give any reasons for your statement that you "don't think this
is right."
Bitwise AND is exactly isomorphic to multiplication in the
field of the integers modulo 2. Compare:

0 & 0 = 0 0 * 0 = 0
0 & 1 = 0 0 * 1 = 0
1 & 0 = 0 1 * 0 = 0
1 & 1 = 1 1 * 1 = 1

See? Same thing.

yeah, sorry. I was thinking modulus % operator
when what it meant was in base2.

Do you mean "they" (perhaps a math textbook?) used the
logical AND operator, looking something like an upside-down wide V,
or the exponentiation operator "up-arrow," displayed on a computer
screen as "^"?
In C, logical AND is spelled &&, exponentiation is spelled "pow"
(after #including <math.h>), and the operator spelled ^ is pronounced
"bitwise XOR."

[sig includes]
#include <stdio.h>
#define p(s) printf(#s" endian")
int main(void){int v=1;*(char*)&v?p(Little) : p(Big); return 0;}

Oh yeah, and that code isn't c.l.c-compliant. :) [ISO standard
C doesn't really give any useful definitions regarding endianness,
nor does it guarantee that the attempted evaluation of *(char*)&v
won't invoke undefined behavior on the DeathStation 9000.]

-Arthur
 
L

Leor Zolman

so when you have a struct declaration of:

struct foo { int example; struct bar *ptr; };

and then supply your definition:

struct foo baz;

baz is an actual object, example is an actual object
but what about "ptr" ? it is not a valid pointer object
right?

Note how you switched terminology when you got to "ptr"? If you'd gone
on to say, "...it is not an actual object, right"? You'd have been
wrong, because it is. But it is not a valid pointer.

For a pointer,
SOMETHING *p;
p can represent an lvalue, and so can *p. But they're distinct.
-leor


so it cannot hold:

baz.ptr = NULL; /* can't hold the value of NULL? */

and also under such a circumstance, why is this even
allowed in this regard?

If the type definition is never given for "struct bar"
then the type may never be completed
so in essence you end up with a completely useless
incomplete type in this regard.

it would seem logical for a compiler
to have to issue some type of diagnostic
if it knows the type is never completed.
Yes, but I have no idea what, because, like the OP, you didn't
give any reasons for your statement that you "don't think this
is right."
Bitwise AND is exactly isomorphic to multiplication in the
field of the integers modulo 2. Compare:

0 & 0 = 0 0 * 0 = 0
0 & 1 = 0 0 * 1 = 0
1 & 0 = 0 1 * 0 = 0
1 & 1 = 1 1 * 1 = 1

See? Same thing.

yeah, sorry. I was thinking modulus % operator
when what it meant was in base2.

but they used ^ for AND

Do you mean "they" (perhaps a math textbook?) used the
logical AND operator, looking something like an upside-down wide V,
or the exponentiation operator "up-arrow," displayed on a computer
screen as "^"?
In C, logical AND is spelled &&, exponentiation is spelled "pow"
(after #including <math.h>), and the operator spelled ^ is pronounced
"bitwise XOR."

[sig includes]
#include <stdio.h>
#define p(s) printf(#s" endian")
int main(void){int v=1;*(char*)&v?p(Little) : p(Big); return 0;}

Oh yeah, and that code isn't c.l.c-compliant. :) [ISO standard
C doesn't really give any useful definitions regarding endianness,
nor does it guarantee that the attempted evaluation of *(char*)&v
won't invoke undefined behavior on the DeathStation 9000.]

-Arthur

Leor Zolman
BD Software
(e-mail address removed)
www.bdsoft.com -- On-Site Training in C/C++, Java, Perl & Unix
C++ users: Download BD Software's free STL Error Message
Decryptor at www.bdsoft.com/tools/stlfilt.html
 
M

Malcolm

pete said:
There are none in C.
type int, has exactly 1 sign bit and at least 15 value bits, always.
Though I once had a small embedded system that worked on 8-bit ints, so the
requirements of the standard and actual practise don't always match.
 
J

Joe Wright

Leor said:
Note how you switched terminology when you got to "ptr"? If you'd gone
on to say, "...it is not an actual object, right"? You'd have been
wrong, because it is. But it is not a valid pointer.

For a pointer,
SOMETHING *p;
p can represent an lvalue, and so can *p. But they're distinct.
-leor
Hello Leor. Welcome to the fray. I remember you as the author of BDS C
for CP/M 80 a quarter century ago. Or is it only 20 years? Or do I have
you mixed up with the other Leor Zolman? :)
 
M

Martin Ambuhl

Malcolm said:
Though I once had a small embedded system that worked on 8-bit ints, so the
requirements of the standard and actual practise don't always match.

Any implementation that has CHAR_BIT == 8 has 8-bit integers. No C
implementation is *required* to have 8-bit integers, but any *may*. That
no flavor of int can fit into 8 bits is a red herring.
It is also false thatYour implementation does not define the C language.
 
M

Malcolm

Martin Ambuhl said:
Your implementation does not define the C language.
To an extent it does. If the term "C" is used to refer to the language, then
that become part of the meaning of the term. Of course the implementation is
not part of the formal, ANSI definition of the language, but even ANSI
cannot successfully define C because they cannot force implemetation of
their standards :)
 
L

Leor Zolman

Hello Leor. Welcome to the fray. I remember you as the author of BDS C
for CP/M 80 a quarter century ago. Or is it only 20 years? Or do I have
you mixed up with the other Leor Zolman? :)

You must mean my evil anti-matter twin; This Leor only codes ANSI/ISO
C (always including all conceivable headers), and wouldn't be caught
dead _using_ a compiler that treats all externs like a single unnamed
FORTRAN common block and lacks initialization, longs or floats, let
alone _writing_ one...
-leor #2

P.S. Exactly 25 years ago, Leor #1 was about 1/2-way through coding
the first version of BDS C; it passed its first serious test,
compiling and running the Othello program he had gotten sick of trying
to hand-convert into 8080 assembly language, in early April of '79.

P.P.S. If you meant to send that post as a personal email. _please_
don't tell me... ;-)



Leor Zolman
BD Software
(e-mail address removed)
www.bdsoft.com -- On-Site Training in C/C++, Java, Perl & Unix
C++ users: Download BD Software's free STL Error Message
Decryptor at www.bdsoft.com/tools/stlfilt.html
 
P

Papadopoulos Giannis

pete said:
They are both in stdlib.h. All of the macros,
which are needed to describe any standard library function,
are defined in the header corresponding to the function.
Therefore, all standard library headers which have the prototype
for any function capable of returning NULL, define NULL too.
malloc takes a size_t argument,
so you can assume that size_t is defined in stdlib.h, also.
But is NULL defined in stdio.h as mr. O' Dwyer suggested?
We don't generally assume a 32 bit machine, here.
If int has any padding, it's possible that *(char*)&v
might be signed and also a trap representation of negative zero.

It just checks if the first byte of an int is 0 or anything else.. If it
is zero, it is a big endian machine, else a little endian..

And I am not assuming that it is a 32-bit machine.. I am only using the
first byte.. So being 32-bit or 64-bit is irrelevant...


--
#include <stdio.h>
#define p(s) printf(#s" endian")
int main(void){int v=1;*(char*)&v?p(Little):p(Big);return 0;}

Giannis Papadopoulos
http://dop.users.uth.gr/
University of Thessaly
Computer & Communications Engineering dept.
 
D

Dik T. Winter

> Mantorok Redgormor wrote: ....
>
> I don't think this is right... Am I missing something?

It was probably in a text using mathematical notation. It is
equivalent to pointwise multiplication in an n-dimensional
vector space over Z_2. Or (to be more precise) an operation
from Z_2<sup>n * Z_2<sup>n -> Z_2<sup>n (where _ means subscript
and said:
>
> the ^ is not AND operator, it is the XOR operator...
> and it doesn't seem to work either...

Not in mathematical notation. There ^ indicates AND. How ^
came to be XOR in C is interesting, because it is AND in the
Algol languages.
 
M

Mantorok Redgormor

Leor Zolman said:
Note how you switched terminology when you got to "ptr"? If you'd gone
on to say, "...it is not an actual object, right"? You'd have been
wrong, because it is. But it is not a valid pointer.

I think you missed something.
"ptr" can never be an object since
its type definition is never complete.

so it remains an incomplete type.

though I can't find the relevant sections in the standard
that say that at this time.



--
nethlek
For a pointer,
SOMETHING *p;
p can represent an lvalue, and so can *p. But they're distinct.
-leor


so it cannot hold:

baz.ptr = NULL; /* can't hold the value of NULL? */

and also under such a circumstance, why is this even
allowed in this regard?

If the type definition is never given for "struct bar"
then the type may never be completed
so in essence you end up with a completely useless
incomplete type in this regard.

it would seem logical for a compiler
to have to issue some type of diagnostic
if it knows the type is never completed.
My second question is not related to undefined behavior.
I read that bitwise AND is equivalent to
"Multiplication modulus two" They made some notation
with something that looked like two Zs'

I don't think this is right... Am I missing something?

Yes, but I have no idea what, because, like the OP, you didn't
give any reasons for your statement that you "don't think this
is right."
Bitwise AND is exactly isomorphic to multiplication in the
field of the integers modulo 2. Compare:

0 & 0 = 0 0 * 0 = 0
0 & 1 = 0 0 * 1 = 0
1 & 0 = 0 1 * 0 = 0
1 & 1 = 1 1 * 1 = 1

See? Same thing.

yeah, sorry. I was thinking modulus % operator
when what it meant was in base2.

but they used ^ for AND

Do you mean "they" (perhaps a math textbook?) used the
logical AND operator, looking something like an upside-down wide V,
or the exponentiation operator "up-arrow," displayed on a computer
screen as "^"?
In C, logical AND is spelled &&, exponentiation is spelled "pow"
(after #including <math.h>), and the operator spelled ^ is pronounced
"bitwise XOR."

[sig includes]
#include <stdio.h>
#define p(s) printf(#s" endian")
int main(void){int v=1;*(char*)&v?p(Little) : p(Big); return 0;}

Oh yeah, and that code isn't c.l.c-compliant. :) [ISO standard
C doesn't really give any useful definitions regarding endianness,
nor does it guarantee that the attempted evaluation of *(char*)&v
won't invoke undefined behavior on the DeathStation 9000.]

-Arthur

Leor Zolman
BD Software
(e-mail address removed)
www.bdsoft.com -- On-Site Training in C/C++, Java, Perl & Unix
C++ users: Download BD Software's free STL Error Message
Decryptor at www.bdsoft.com/tools/stlfilt.html
 
L

Leor Zolman

I think you missed something.
"ptr" can never be an object since
its type definition is never complete.

The point I was trying to make is that "ptr", being a pointer, is
itself just like a "primitive type". It cannot be incomplete. However,
it can be defined to /point/ to something whose type is still
incomplete at the time of ptr's definition.
so it remains an incomplete type.

"struct bar" is the incomplete type, /not/ ptr.
though I can't find the relevant sections in the standard
that say that at this time.

Just /think/ about it. Doesn't the compiler have all the information
it needs to place ptr into a fixed location in memory of known size?
It is the size of a pointer; whatever that is, it is /known/.
-leor
 
A

Arthur J. O'Dwyer

It was probably in a text using mathematical notation. It is
equivalent to pointwise multiplication in an n-dimensional
vector space over Z_2. Or (to be more precise) an operation
from Z_2<sup>n * Z_2<sup>n -> Z_2<sup>n (where _ means subscript
and <sup> means superscript).

Nitpick: I would have said it was an operation *from*
(Z_2)^n * (Z_2)^n *to* (Z_2)^n, or an operation *in*
(Z_2)^n * (Z_2)^n -> (Z_2)^n. I don't know if that's a widely
used mode of speech, but it makes more sense to me, syntactically
speaking.
Not in mathematical notation. There ^ indicates AND.

As I said (and you snipped), ^ in mathematics quite often
indicates exponentiation, and *never* logical AND. The usual
symbol for logical AND is a sort of inverted V, as seen here:
http://mathworld.wolfram.com/aimg1694.gif
which is not the same symbol as the caret or up-arrow, as seen here:
"A ^ B"
Well, okay, I couldn't find any images of that symbol. But you
can get both of them in LaTeX with \land and \^{}, respectively.

How ^
came to be XOR in C is interesting, because it is AND in the
Algol languages.

Same objection as above. The Algol language described in the one
book I own on the subject uses the inverted-V AND operator seen in
the image above, IIRC.
Incidentally, the mathematical symbol for XOR is often a plus sign
with a circle around it, to indicate that it behaves like addition
in the field (Z_2)^n. I have no idea where the idea of using ^ for
XOR came from, except that ^ kind of looks like the lower half of a
superscript "X". :)

-Arthur
 
P

Peter Nilsson

....
[sig includes]
#include <stdio.h>
#define p(s) printf(#s" endian")
int main(void){int v=1;*(char*)&v?p(Little) : p(Big); return 0;}

Oh yeah, and that code isn't c.l.c-compliant. :) [ISO standard
C doesn't really give any useful definitions regarding endianness,
nor does it guarantee that the attempted evaluation of *(char*)&v
won't invoke undefined behavior on the DeathStation 9000.]

It would seem to be C99 complient. [Even if the output won't necessarily be
meaningful.]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,831
Latest member
HealthSmartketoReviews

Latest Threads

Top