Discussion:
Is this valid C?
(too old to reply)
BartC
2017-02-18 00:43:49 UTC
Permalink
Raw Message
(I've left the subject general in case anything else comes up then I
won't need a new thread each time.)

Is the comparison valid here:

char *p;

if (p > 0) ....

Some compilers complain (one in three), others don't.

I've looked at the standard (6.5.8p2) but according to that you're not
even allowed to compare two integers! That's what it looked like at
first anyway. Presumably 'real' type means arithmetic types not just floats.

However it then goes on to say something about both pointers pointing
into the same object, so it would be unlikely that 0 belongs in the same
object as p. Yet, with (p >= 0), you might expect this to yield 1 when p
is zero.
--
Bartc
Ben Bacarisse
2017-02-18 02:41:15 UTC
Permalink
Raw Message
Post by BartC
(I've left the subject general in case anything else comes up then I
won't need a new thread each time.)
char *p;
It's better to initialise objects in example or you add another reason
for something being undefined.
Post by BartC
if (p > 0) ....
No, it's not, but no diagnostic is required.
Post by BartC
Some compilers complain (one in three), others don't.
I've looked at the standard (6.5.8p2) but according to that you're not
even allowed to compare two integers! That's what it looked like at
first anyway. Presumably 'real' type means arithmetic types not just floats.
No. The real types and the arithmetic types are different sets of
types:

"The integer and real floating types are collectively called real
types."

Whereas

"Integer and floating types are collectively called arithmetic
types. Each arithmetic type belongs to one type domain: the real type
domain comprises the real types, the complex type domain comprises the
complex types."
Post by BartC
However it then goes on to say something about both pointers pointing
into the same object, so it would be unlikely that 0 belongs in the
same object as p. Yet, with (p >= 0), you might expect this to yield 1
when p is zero.
It's undefined by C. 0 does not point to any object so none of the
relational operators can be used with it in a defined way.
--
Ben.
David Brown
2017-02-18 10:47:18 UTC
Permalink
Raw Message
Post by BartC
(I've left the subject general in case anything else comes up then I
won't need a new thread each time.)
char *p;
if (p > 0) ....
Some compilers complain (one in three), others don't.
I've looked at the standard (6.5.8p2) but according to that you're not
even allowed to compare two integers! That's what it looked like at
first anyway. Presumably 'real' type means arithmetic types not just floats.
6.2.5, paragraph 17 and 18 is what you are looking for. My pdf reader
has a fantastic feature that helped here - the "search" function.
Post by BartC
However it then goes on to say something about both pointers pointing
into the same object, so it would be unlikely that 0 belongs in the same
object as p. Yet, with (p >= 0), you might expect this to yield 1 when p
is zero.
(No need for me to repeat Ben's explanation.)
Andrey Tarasevich
2017-02-18 18:08:18 UTC
Permalink
Raw Message
Post by BartC
(I've left the subject general in case anything else comes up then I
won't need a new thread each time.)
char *p;
if (p > 0) ....
Some compilers complain (one in three), others don't.
I've looked at the standard (6.5.8p2) but according to that you're not
even allowed to compare two integers! That's what it looked like at
first anyway. Presumably 'real' type means arithmetic types not just floats.
"*6.5.8 Relational operators*

*Constraints*

2 One of the following shall hold:
— both operands have real type; or
— both operands are pointers to qualified or unqualified versions of
compatible object types."

No need to look further. The code is invalid.

'p' is not of real type.

'0' is not an operand of pointer type. Usage of null-pointer constant in
pointer contexts requires an explicit permission, as the one present in
constraints of equality operators.
--
Best regards,
Andrey Tarasevich
BartC
2017-02-18 23:30:20 UTC
Permalink
Raw Message
sizeof

I've just started with this and it's looking tricky.

Assuming that A,B,C are all arrays, then trials show that:

sizeof (C) C stays an array

sizeof (A,B,C) A,B,C all converted to pointers

sizeof x?B:C B,C both converted to pointers

Presumably C is not a direct operand of sizeof in the last two cases.
But here:

struct {int a, C[10];} S;

sizeof S.C

C is treated as an array, even though it's not a direct operand of
sizeof either. I guess the same applies to the last in a chain of ".",
"->" and "[]" operators (I don't think "()" can yield an array type).

So what are the rules? Does special behaviour required by sizeof (and
_Alignof etc) only come into play when the last thing done in the
subexpression forming its operand, involves converting an array to a
pointer? But then that would apply to 'sizeof (A,B,C)' too!
--
bartc
j***@verizon.net
2017-02-18 23:50:35 UTC
Permalink
Raw Message
Post by BartC
sizeof
I've just started with this and it's looking tricky.
sizeof (C) C stays an array
sizeof (A,B,C) A,B,C all converted to pointers
sizeof x?B:C B,C both converted to pointers
Presumably C is not a direct operand of sizeof in the last two cases.
struct {int a, C[10];} S;
sizeof S.C
C is treated as an array, even though it's not a direct operand of
sizeof either. I guess the same applies to the last in a chain of
The key issue is that A,B,C is a series of comma expressions, with a result that depends upon the types of it's operands. ".",
Post by BartC
"->" and "[]" operators (I don't think "()" can yield an array type).
So what are the rules? Does special behaviour required by sizeof (and
_Alignof etc) only come into play when the last thing done in the
subexpression forming its operand, involves converting an array to a
pointer? But then that would apply to 'sizeof (A,B,C)' too!
The rule is that "Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue." (6.3.2.1p3)

In sizeof(A,B,C), neither A, nor B, nor C are operands of sizeof, they are operands of the comma operator. As a result, each of them gets converted to pointers to the first element of the corresponding array. The final comma expression has a value that points at the first element of C. sizeof(A,B,C) therefore gives the size of such a pointer.

In sizeof(S.C), neither S nor C are operands of sizeof. However, equally important, C is not, in this context, an expression of array type. The member selection operators are special, because their right operand is a member name, not an expression. A member name is not converted into a pointer to the first element of the array, even if the member has array type. This is good, because such a pointer would not be an acceptable right operand for the member selection operators. On the other hand, the entire expression S.C is an lvalue of array type, and would undergo that conversion in most other contexts. However, in this context the entire expression is the direct operand of the sizeof expression, and therefore also does not get converted.
BartC
2017-02-19 00:53:43 UTC
Permalink
Raw Message
Post by j***@verizon.net
Post by BartC
struct {int a, C[10];} S;
sizeof S.C
C is treated as an array, even though it's not a direct operand of
sizeof either. I guess the same applies to the last in a chain of
The key issue is that A,B,C is a series of comma expressions, with a result that depends upon the types of it's operands. ".",
Post by BartC
"->" and "[]" operators (I don't think "()" can yield an array type).
So what are the rules?
The rule is that "Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue." (6.3.2.1p3)
In sizeof(A,B,C), neither A, nor B, nor C are operands of sizeof, they are operands of the comma operator. As a result, each of them gets converted to pointers to the first element of the corresponding array. The final comma expression has a value that points at the first element of C. sizeof(A,B,C) therefore gives the size of such a pointer.
In sizeof(S.C), neither S nor C are operands of sizeof. However, equally important, C is not, in this context, an expression of array type. The member selection operators are special, because their right operand is a member name, not an expression. A member name is not converted into a pointer to the first element of the array, even if the member has array type. This is good, because such a pointer would not be an acceptable right operand for the member selection operators. On the other hand, the entire expression S.C is an lvalue of array type, and would undergo that conversion in most other contexts. However, in this context the entire expression is the direct operand of the sizeof expression, and therefore also does not get converted.
OK, thanks. So I'll special case ".", "->" and "[]" operators when the
result is a direct operand of sizeof.

(It's going to be awkward to stop the array->pointer conversions
happening, as an operator can't easily tell if it is itself an immediate
operand of sizeof, so I will have to store the array information just in
case it needs to be recovered.)
--
bartc
Andrey Tarasevich
2017-02-19 00:01:13 UTC
Permalink
Raw Message
Post by BartC
So what are the rules? Does special behaviour required by sizeof (and
_Alignof etc) only come into play when the last thing done in the
subexpression forming its operand, involves converting an array to a
pointer? But then that would apply to 'sizeof (A,B,C)' too!
The rule is simple: when an array is used as the immediate operand of
'sizeof, '_Alignof' or unary '&', the array remains an array. It does
not decay to pointer.

In your 'sizeof (A,B,C)' example, array 'C' is an operand of ','
operator. So it decays.
--
Best regards,
Andrey Tarasevich
Keith Thompson
2017-02-19 03:20:43 UTC
Permalink
Raw Message
Post by Andrey Tarasevich
Post by BartC
So what are the rules? Does special behaviour required by sizeof (and
_Alignof etc) only come into play when the last thing done in the
subexpression forming its operand, involves converting an array to a
pointer? But then that would apply to 'sizeof (A,B,C)' too!
The rule is simple: when an array is used as the immediate operand of
'sizeof, '_Alignof' or unary '&', the array remains an array. It does
not decay to pointer.
The _Alignof case is an error in the N1570 draft, corrected in the
published ISO C11 standard. The _Alignof operator can only be applied
to a parenthesized type name (like sizeof), not to an expresion (unlike
sizeof). The reasons for this difference are not clear; I asked Larry
Jones, a committee member, and he didn't know.

(I did some research on the history of alignof; I'll post it in
comp.std.c.)

(The third case where an array expression doesn't decay to a pointer
expression is when it's a string literal in an initializer used to
initialize an array object.)

Note that what's commonly called "decay" is not a run-time type
conversion. It's a compile-time conversion ("adjustment" might have
been clearer) of an array expression to a pointer expression.
Post by Andrey Tarasevich
In your 'sizeof (A,B,C)' example, array 'C' is an operand of ','
operator. So it decays.
BartC's example

struct {int a, C[10];} S;
sizeof S.C

is actually quite straightforward. `S.C` is an expression of
array type. Since that expression is the operand of `sizeof`, it
is not converted to a pointer expression. (`C` by itself is not an
expression at all.)
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
GOTHIER Nathan
2017-02-19 08:41:01 UTC
Permalink
Raw Message
On Sat, 18 Feb 2017 19:20:43 -0800
Post by Keith Thompson
The _Alignof case is an error in the N1570 draft, corrected in the
published ISO C11 standard. The _Alignof operator can only be applied
to a parenthesized type name (like sizeof), not to an expresion (unlike
sizeof). The reasons for this difference are not clear; I asked Larry
Jones, a committee member, and he didn't know.
Did he know the C language before taking the money? :-D
Richard Heathfield
2017-02-19 09:14:20 UTC
Permalink
Raw Message
Post by GOTHIER Nathan
On Sat, 18 Feb 2017 19:20:43 -0800
Post by Keith Thompson
The _Alignof case is an error in the N1570 draft, corrected in the
published ISO C11 standard. The _Alignof operator can only be applied
to a parenthesized type name (like sizeof), not to an expresion (unlike
sizeof). The reasons for this difference are not clear; I asked Larry
Jones, a committee member, and he didn't know.
Did he know the C language before taking the money? :-D
Larry Jones's knowledge of the C language is encyclopaedic, and in all
likelihood far superior to yours. It is certainly vastly superior to mine.

I realise you were trying to make a joke, but it wasn't a terribly good one.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
GOTHIER Nathan
2017-02-19 09:30:44 UTC
Permalink
Raw Message
On Sun, 19 Feb 2017 09:14:20 +0000
Post by Richard Heathfield
Post by GOTHIER Nathan
Did he know the C language before taking the money? :-D
Larry Jones's knowledge of the C language is encyclopaedic, and in all
likelihood far superior to yours. It is certainly vastly superior to mine.
I realise you were trying to make a joke, but it wasn't a terribly good one.
I was half-joking since he can't explain the choice made by the committee which
he's a member...
Keith Thompson
2017-02-19 15:21:58 UTC
Permalink
Raw Message
Post by Richard Heathfield
Post by GOTHIER Nathan
On Sat, 18 Feb 2017 19:20:43 -0800
Post by Keith Thompson
The _Alignof case is an error in the N1570 draft, corrected in the
published ISO C11 standard. The _Alignof operator can only be applied
to a parenthesized type name (like sizeof), not to an expresion (unlike
sizeof). The reasons for this difference are not clear; I asked Larry
Jones, a committee member, and he didn't know.
Did he know the C language before taking the money? :-D
Larry Jones's knowledge of the C language is encyclopaedic, and in all
likelihood far superior to yours. It is certainly vastly superior to mine.
I realise you were trying to make a joke, but it wasn't a terribly good one.
Especially since committee members aren't paid.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
BartC
2017-02-19 11:23:08 UTC
Permalink
Raw Message
Post by BartC
struct {int a, C[10];} S;
sizeof S.C
is actually quite straightforward. `S.C` is an expression of
array type. Since that expression is the operand of `sizeof`, it
is not converted to a pointer expression. (`C` by itself is not an
expression at all.)
Given:

int A[10], B[10], C[10], D[10][6], x,i,j;

aren't (A,B,C) and (x?B?C) and D[i] expressions of array type too?

All, including S.C, can have [j] appended, and effect in all cases is to
index what had been declared as an actual array.
--
Bartc
Keith Thompson
2017-02-19 15:33:00 UTC
Permalink
Raw Message
Post by BartC
Post by BartC
struct {int a, C[10];} S;
sizeof S.C
is actually quite straightforward. `S.C` is an expression of
array type. Since that expression is the operand of `sizeof`, it
is not converted to a pointer expression. (`C` by itself is not an
expression at all.)
int A[10], B[10], C[10], D[10][6], x,i,j;
aren't (A,B,C) and (x?B?C) and D[i] expressions of array type too?
No, no, and maybe, respectively.

In the first, A, B, and C are array expressions, but they're operands
of the commma operator so they decay to pointer expressions, making
(A,B,C) a pointer expression.

In (x?B:C) (fixed typo), B and C are array expressions, but they're
operands of the conditional operator so they decay to pointer
expressions, making (x?B:C) a pointer expression.

D[i] *is* an array expression. It may or may not decay to a pointer
expression, depending on its context.

Whether an array expression decays to a pointer expression is
determined entirely by its context, specifically whether or not
it's the (immediate) operand of a unary `sizeof` or `&` operator
(setting aside the string literal initializer case).
Post by BartC
All, including S.C, can have [j] appended, and effect in all cases is to
index what had been declared as an actual array.
As you surely know, the indexing operator is applied to a pointer
expression, not an array expression. (Of course that pointer
expression is often a decayed array expression).
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Ike Naar
2017-02-19 09:06:15 UTC
Permalink
Raw Message
Post by BartC
sizeof x?B:C B,C both converted to pointers
The sizeof operator takes a unary-expression as its operand, so
the expression above is interpreted as:

(sizeof x) ? B : C

Is that what you intended, or did you mean

sizeof (x ? B : C)

?
BartC
2017-02-19 10:53:23 UTC
Permalink
Raw Message
Post by Ike Naar
Post by BartC
sizeof x?B:C B,C both converted to pointers
The sizeof operator takes a unary-expression as its operand, so
(sizeof x) ? B : C
Is that what you intended, or did you mean
sizeof (x ? B : C)
?
The latter. (My actual code always has ?: with parentheses, but it seems
to be fashionable to leave them off.)
Jerry Stuckle
2017-02-19 14:06:27 UTC
Permalink
Raw Message
Post by Ike Naar
Post by BartC
sizeof x?B:C B,C both converted to pointers
The sizeof operator takes a unary-expression as its operand, so
(sizeof x) ? B : C
Is that what you intended, or did you mean
sizeof (x ? B : C)
?
You are correct, but not for the reason you stated. x ? B : C returns a
single value, so sizeof (x ? B : C) is valid.

However, unary operators such as sizeof have a higher precedence than
the ternary operator, so sizeof is evaluated before ?:.
--
==================
Remove the "x" from my email address
Jerry Stuckle
***@attglobal.net
==================
David Brown
2017-02-19 10:03:29 UTC
Permalink
Raw Message
Post by BartC
sizeof
I've just started with this and it's looking tricky.
sizeof (C) C stays an array
sizeof (A,B,C) A,B,C all converted to pointers
sizeof x?B:C B,C both converted to pointers
It is hard to imagine any possible use for such expressions. When would
one ever need to find the size of something that is not a "thing" - an
object, sub-object, or a type ?
Post by BartC
Presumably C is not a direct operand of sizeof in the last two cases.
struct {int a, C[10];} S;
sizeof S.C
C is treated as an array, even though it's not a direct operand of
sizeof either. I guess the same applies to the last in a chain of ".",
"->" and "[]" operators (I don't think "()" can yield an array type).
So what are the rules? Does special behaviour required by sizeof (and
_Alignof etc) only come into play when the last thing done in the
subexpression forming its operand, involves converting an array to a
pointer? But then that would apply to 'sizeof (A,B,C)' too!
BartC
2017-02-19 12:10:24 UTC
Permalink
Raw Message
Post by David Brown
Post by BartC
sizeof
I've just started with this and it's looking tricky.
sizeof (C) C stays an array
sizeof (A,B,C) A,B,C all converted to pointers
sizeof x?B:C B,C both converted to pointers
It is hard to imagine any possible use for such expressions. When would
one ever need to find the size of something that is not a "thing" - an
object, sub-object, or a type ?
Whether such an expression is useful not is irrelevant. The decision to
convert or not convert an array type to a pointer when sizeof/etc might
be involved can't be based on a 'usefulness' factor!

And an algorithm to do this needs to work for any conceivable expression:

sizeof (cond ? (puts("Sizeof on A"), A) : (puts("sizeof on B"), B));

Testing this however shows no output. But then of course a sizeof
expression is usually not executed.

That would mean that the A,B in (A,B,C) is ignored, while (x?B:C) cannot
be used to selectively take the size of either B or C.

On the other hand, a sizeof expression might be a macro that is also
used elsewhere in a normal executable context.

'sizeof' still seems rather an odd operator, but I just want to emulate
the correct behaviour at the minute not argue about its merits.
--
bartc
Loading...