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

Complex litterals

24 views
Skip to first unread message

Antoine Leca

unread,
Dec 28, 2009, 7:13:41 AM12/28/09
to
Hi,
Meilleurs voeux, Feliz a~no nuevo, Happy New Year,

I am trying to figure out the problem behind Fred Tydeman's N1431
(http://www.open-std.org/JTC1/sc22/wg14/www/docs/n1431.htm, last of a
growing serie.)

Part a)

Particularly, after reading 6.2.5p13 (unchanged in current draft),
I fail to see exactly why the following do not "work"

#include <math.h> /* for INFINITY, NAN manifest constants */

int foo()
{
float _Complex fc0 = (float _Complex){INFINITY, NAN};
double _Complex dc0 = (double _Complex){3.0, 4.0};


I realize that "Proposal number two" in N1431 is similar to this very
mechanism, to put in clear text in the Standard would certainly be
welcome, and it also makes it lighter for initializations;
but I am trying to figure out what is really missing or contradictory in
the current (C99/N1425) text for the above to be valid.


Part b)

Can such a compound litteral be used outside the body of a function?
i.e. assuming the above is (made) valid, can it be enhanced to

static
double _Complex dc0 = (double _Complex){3.0, 4.0};

If yes, why is Fred worring about interferences between unnamed objects
and initializations:
The downside of this usage is [...] an unnamed object is
created (so, cannot be used for initialization of static objects),


Thanks in advance for your explanations.


Antoine

Fred J. Tydeman

unread,
Dec 28, 2009, 11:36:49 AM12/28/09
to
On Mon, 28 Dec 2009 12:13:41 UTC, Antoine Leca <ro...@localhost.invalid> wrote:

> I am trying to figure out the problem behind Fred Tydeman's N1431
> (http://www.open-std.org/JTC1/sc22/wg14/www/docs/n1431.htm, last of a
> growing serie.)
>
> Part a)
>
> Particularly, after reading 6.2.5p13 (unchanged in current draft),
> I fail to see exactly why the following do not "work"
>
> #include <math.h> /* for INFINITY, NAN manifest constants */
>
> int foo()
> {
> float _Complex fc0 = (float _Complex){INFINITY, NAN};
> double _Complex dc0 = (double _Complex){3.0, 4.0};
>
>
> I realize that "Proposal number two" in N1431 is similar to this very
> mechanism, to put in clear text in the Standard would certainly be
> welcome, and it also makes it lighter for initializations;
> but I am trying to figure out what is really missing or contradictory in
> the current (C99/N1425) text for the above to be valid.

The above are valid compound literals.
They are also valid initializers for 'auto' variables.
So, the above should work.



> Part b)
>
> Can such a compound litteral be used outside the body of a function?
> i.e. assuming the above is (made) valid, can it be enhanced to
>
> static
> double _Complex dc0 = (double _Complex){3.0, 4.0};
>
> If yes, why is Fred worring about interferences between unnamed objects
> and initializations:
> The downside of this usage is [...] an unnamed object is
> created (so, cannot be used for initialization of static objects),

By 6.7.9 Initialization, paragraph 4, static objects require constant expressions
for initialization.

6.6 Constant expressions, paragraphs 7 and 8, an arithmetic constant expression
is required for initialization. A compound literal does NOT meet the requirements
of paragraph 8.

Perhaps another way to solve our problem is to alter 6.6#8 to allow compound
literal of floating constants to be valid.
---
Fred J. Tydeman Tydeman Consulting
tyd...@tybor.com Testing, numerics, programming
+1 (775) 358-9748 Vice-chair of PL22.11 (ANSI "C")
Sample C99+FPCE tests: http://www.tybor.com
Savers sleep well, investors eat well, spenders work forever.

James Kuyper

unread,
Dec 30, 2009, 8:03:53 AM12/30/09
to
Antoine Leca wrote:
> Hi,
> Meilleurs voeux, Feliz a~no nuevo, Happy New Year,
>
> I am trying to figure out the problem behind Fred Tydeman's N1431
> (http://www.open-std.org/JTC1/sc22/wg14/www/docs/n1431.htm, last of a
> growing serie.)
>
> Part a)
>
> Particularly, after reading 6.2.5p13 (unchanged in current draft),
> I fail to see exactly why the following do not "work"
>
> #include <math.h> /* for INFINITY, NAN manifest constants */
>
> int foo()
> {
> float _Complex fc0 = (float _Complex){INFINITY, NAN};
> double _Complex dc0 = (double _Complex){3.0, 4.0};

It may help, and will certainly simplify the discussion, to point out
that, per 6.5.2.5p6 your use of compound literals can be implemented by
the compiler by generating the equivalent of the following code, and
therefore has all of the same defects as that code:

float _Complex _unnamed_temp1 = {INFINITY, NAN};
float _Complex fc0 = unnamed_temp1;
float _Complex _unnamed_temp2 = {3.0, 4.0};
float _Complex dc0 = _unnamed_temp2;

In other words, your code is functionally equivalent to
float _Complex fc0 = {INFINITY, NAN};
double _Complex dc0 = {3.0, 4.0};

The only difference is that (ignoring the constraint violations
explained below) your version nominally uses twice as much memory. Since
there's no way to access _unnamed_temp1 or _unnamed_temp2 once they've
been used to initialize fc0 and dc0, I'd expect any decent compiler to
optimize them away; but in principle they are supposed to be there.

> I realize that "Proposal number two" in N1431 is similar to this very
> mechanism, to put in clear text in the Standard would certainly be
> welcome, and it also makes it lighter for initializations;
> but I am trying to figure out what is really missing or contradictory in
> the current (C99/N1425) text for the above to be valid.

The fundamental problem is that while "Each complex type has the same
representation and alignment requirements as an array type containing
exactly two elements of the corresponding real type; the first element
is equal to the real part, and the second element to the imaginary part,
of the complex number.", there is nothing in the current standard that
allows them to be initialized using the same syntax as an array of
exactly two elements.

The grammar in 6.7.8p1 makes it clear that the comma in an initializer
list separates different initializers. Your compound literals therefore
contain two initializers each. If you were creating a compound literal
of array type, they could be initializers for different elements of that
array. However, there's nothing saying that they can be the real and
imaginary components of the same complex number. Note: I cannot provide
a citation for this assertion - it is amazingly difficult to point to
the particular location in a document where something is NOT said :-).
However, if the standard did say something about initializing complex
numbers using the same notation as for a 2-element array, I would expect
the relevant wording to be in either section 6.2.5 or 6.7.8; there's
nothing about it in either place.

Your first initializer list provides values for two different complex
numbers: the first one initialized with the expression (float
_Complex)INFINITY, the second with (float _Complex)NAN. Therefore, it
violates 6.5.2.5p2: "No initializer shall attempt to provide a value for
an object not contained within the entire unnamed object specified by
the compound literal."; the second initializer in the list has nothing
to initialize. The same logic applies for your second initializer list.

If you're thinking that a complex number counts should count as two
scalars, the relevant clauses are 6.2.5p11, which says that complex
types are floating types; 6.2.5p19, which says that floating types are
arithmetic types; and 6.2.5p12, which says arithmetic types are scalar
types.

> Part b)
>
> Can such a compound litteral be used outside the body of a function?
> i.e. assuming the above is (made) valid, can it be enhanced to
>
> static
> double _Complex dc0 = (double _Complex){3.0, 4.0};

6.5.2.5p4: If the compound literal occurs outside the body of a
function, the initializer list shall consist of constant expressions."

Therefore, the fact that your compound literal occurs outside the body
of a function is not a problem. It has two other problems; the problem
described above due to the fact that it has too many initializers, and
the problem described below:

> If yes, why is Fred worring about interferences between unnamed objects
> and initializations:
> The downside of this usage is [...] an unnamed object is
> created (so, cannot be used for initialization of static objects),

6.7.8p4: "All the expressions in an initializer for an object that has
static storage duration shall be constant expressions or string literals."

The value of an object (named or unnamed) is not a constant expression,
not even if that object is created by a compound literal. In C++, an
object declared as 'const' and initialized with a constant expression
qualifies itself as a constant expression, but there's no such rule in C.

jacob navia

unread,
Dec 30, 2009, 5:04:16 PM12/30/09
to
Fred J. Tydeman a �crit :
[snip]

I have pointed to this problem before.

The only sensible solution is to standardize existing practice
and have complex numbers use the "i" suffix for the imaginary
part.

float _Complex m = 2.3+4.6i;

This

1) Eliminates the need to include <complex.h> to be able
to recognize a complex constant. Because now if you write
<file foo.c>
double _Complex b = 1.2+4.5*I;
<end of file>
You get "undefined identifier 'I'". Not very good.

2) All the problems and ambiguities disappear. New constants
are needed though: NAN_I INFINITY_I, that could be defined
as NAN*1.0i and INFINITY*1.0i

I think this would be the simplest and most intuitive solution.

Antoine Leca

unread,
Dec 31, 2009, 4:59:31 AM12/31/09
to
Thanks James. As always, your detailled answer did contribute much to my
enlightment.

James Kuyper wrote:


>Antoine Leca wrote:
>> int foo() {
>> float _Complex fc0 = (float _Complex){INFINITY, NAN};
>> double _Complex dc0 = (double _Complex){3.0, 4.0};
>

> your code is functionally equivalent to
> float _Complex fc0 = {INFINITY, NAN};
> double _Complex dc0 = {3.0, 4.0};
>
> The only difference is that (ignoring the constraint violations
> explained below) your version nominally uses twice as much memory.

OK, this is one clear point I did not have in mind. So using compound
litterals where one wants complex litterals is doomed to be a bad idea.

(Except of course if that syntax of a compound of complex types is
special cased and carried away to 6.4.x, to express there the presently
missing "complex constant/litteral". But it is not a small change, and
your remark about the unnecessary temporary/unnamed object leads me to
think it could rather be a curse. N1431 proposal 2 is probably less
ambitious yet more clear-cut, and it ends at about the very same point.)


>> If yes, why is Fred worring about interferences between unnamed objects
>> and initializations:
>> The downside of this usage is [...] an unnamed object is
>> created (so, cannot be used for initialization of static objects),
>
> 6.7.8p4: "All the expressions in an initializer for an object that has
> static storage duration shall be constant expressions or string literals."

Agreed so far.

> The value of an object (named or unnamed) is not a constant expression,
> not even if that object is created by a compound literal.

This is where I have a doubt.

6.6p7 and p8 apply here, which say:
7 More latitude is permitted for constant expressions in
initializers. Such a constant expression shall be, or evaluate
to, one of the following:
— an arithmetic constant expression,
[rest omitted]

8 An /arithmetic constant expression/ shall have arithmetic type
and shall only have operands that are integer constants,
floating constants, enumeration constants, character
constants, and /sizeof/ expressions. Cast operators in an
arithmetic constant expression shall only convert arithmetic
types to arithmetic types, except as part of an operand to a
/sizeof/ operator whose result is an integer constant.

First, the type of a complex litteral would be complex type (6.2.5p11),
hence a floating type, hence an arithmetic type (6.2.5p18); so it
matches this part (first line of p8 above).

I read a compound litteral to be an expression (described in 6.5),
subclassified as postfix operator (6.5.2); note here that compound
litteral is not between the list of "prohibited" operators in 6.6p3
(perhaps it should); similarly, the semantics of the compound litteral
avoids the use of "cast" to describe the parenthetized type name.

So we have to go one level lower. And this is where I have a big doubt.
The lower layer involves an initializer; but I fail to see any
prohibition for it to enter into a constant expression. Clearly the
basic problem here is that the body of clause 6.6 was written for C90,
without compound litterals in 6.5's line of sight, and this may yield
uncertainity and doubt. However, I did not check the archives on this
one, so perhaps (probably) this debate already took place; in such a
case, I should appreciate pointers.

Finally, note that 6.5.2.5p3 and p6 expressly forecast the use of
compounds litterals outside the body of a function, and I believe that
almost any such occurence have to be some form of constant expressions
(because C does not require the use of constructors of any kind); an
obvious exception to "almost" are the "not evaluated uses" like in
sizeof, which would be quite silly here.


Antoine

James Kuyper

unread,
Jan 1, 2010, 8:59:06 AM1/1/10
to
Antoine Leca wrote:
> Thanks James. As always, your detailled answer did contribute much to my
> enlightment.
>
> James Kuyper wrote:
>> Antoine Leca wrote:
...

Your question was specifically about why this code wouldn't work under
the standard as it currently is written. As currently written, C does
not have complex literals. The closest it comes is floating constants,
and per 6.4.4.2p4, they can only have types float, double, or long
double. The grammar (6.4.4.2p1) doesn't even provide a mechanism for
identifying the value of the literal as having complex or imaginary types.

My response was specifically about the use of a compound literal, which
both creates an object, and has a value which is the value of that
object. To simplify the explanation, I'll use a valid compound literal,
rather than the ones you were suggesting. What I was saying is that

float _Complex fc0 = (float _Complex){3.0};

is equivalent to

float _Complex temp = 3.0;
float _Complex fc0 = temp;

and would therefore be disallowed for the same reason: 'temp' doesn't
qualify as any of the permitted types of operands is 6.6p8. It isn't any
type of constant, nor is it a sizeof expression.

However, the expression 5 + 3 * 2 also has an operand (3*2) which
doesn't qualify, yet I would be surprised by any compiler which refused
to accept 5 + 3 * 2 as an arithmetic constant expression. I think it is
widely understood, and possibly stated somewhere in a DR, that the
restrictions on operands in 6.6p8 apply only to operands which do not
have sub-expressions - or possibly I'm just missing something that
allows 3*2.

> I read a compound litteral to be an expression (described in 6.5),

> subclassified as postfix operator (6.5.2); ...

I had not thought about the fact that compound literals are listed as
one of the types of postfix operators, when I made my previous comment.
I thought about it entirely in terms of the equivalent code which would
be a constraint violation. However, I now think that 6.6p8 should be
interpreted as allowing a compound literal as an an arithmetic constant
expression, so long as it's type and initialization expressions meet the
other requirements of that section. . However, gcc (when put into the
most nearly C99-conforming mode that it has) disagrees, so I could be
mistaken.

Antoine Leca

unread,
Jan 4, 2010, 7:46:31 AM1/4/10
to
James Kuyper wrote:
> Your question was specifically about why this code wouldn't work under
> the standard as it currently is written.

Yes. Sorry to have asked two questions in a single post, and now the
discussion is focusing on the second part, the first one introduces
unncessary problems. I apologize for that. I also just realize that
the subject was misleading, this is now corrected.
So please let's focus on (otherwise valid) compound litterals to be used
as initializers.


> Antoine Leca wrote:


>> James Kuyper wrote:
>>> The value of an object (named or unnamed) is not a constant expression,
>>> not even if that object is created by a compound literal.
>>
>> This is where I have a doubt.

<big snip of irrelevant part>


> What I was saying is that
>
> float _Complex fc0 = (float _Complex){3.0};
>
> is equivalent to
>
> float _Complex temp = 3.0;
> float _Complex fc0 = temp;
>
> and would therefore be disallowed for the same reason: 'temp' doesn't
> qualify as any of the permitted types of operands is 6.6p8. It isn't any
> type of constant, nor is it a sizeof expression.
>
> However, the expression 5 + 3 * 2 also has an operand (3*2) which
> doesn't qualify, yet I would be surprised by any compiler which refused
> to accept 5 + 3 * 2 as an arithmetic constant expression. I think it is
> widely understood, and possibly stated somewhere in a DR, that the
> restrictions on operands in 6.6p8 apply only to operands which do not
> have sub-expressions - or possibly I'm just missing something that
> allows 3*2.

I do not follow you here. 6.6 certainly allows for sub-operations?!


>> I read a compound litteral to be an expression (described in 6.5),
>> subclassified as postfix operator (6.5.2); ...
>
> I had not thought about the fact that compound literals are listed as
> one of the types of postfix operators, when I made my previous comment.
> I thought about it entirely in terms of the equivalent code which would
> be a constraint violation.

Yes. And it seems many people are doing the same reasonning (more about
this below).
Since I started from another starting point I am differently biased; and
I still do not see where it is stated or implied the state of affairs as
you understand them.


> However, I now think that 6.6p8 should be
> interpreted as allowing a compound literal as an an arithmetic constant
> expression, so long as it's type and initialization expressions meet the
> other requirements of that section.

So I read you as thinking the above initializer might be valid, as the
Standard reads?

I spotted two discussions in early 2008 this about at
http://osdir.com/ml/comp.compilers.clang.devel/2008-01/ available
through news://news.gmane.org/gmane.comp.compilers.clang.devel,
starting at <news:43A3FB85-F8DB-43D8...@apple.com> and
<news:f5aa3e9b0801250929s48f...@mail.gmail.com>; the
latter contains "Per the standard, a compound literal is not a constant
expression, period." Pretty much to the point, I would say. Yet I prefer
demonstrations to assertions. ;-)


Do not take me wrong: if "allowed" is the correct reading, I think this
is a bug in the Standard, since apparently many knowledgeable people are
thinking compound literals should *not* be allowed as constants, and I
failed to see many (knowledgeable people, that is) in the other camp; so
the current Standard text would violate the principe of least surprise.


> However, gcc (when put into the most nearly C99-conforming mode that
> it has) disagrees, so I could be mistaken.

Perhaps a bug; is it time to start the discussion there, with more
people involved?

Unfortunately I do not have a recent build of GCC at hand. I also see
that "complex support" in http://gcc.gnu.org/c99status.html is marked
"done", while "broken" in http://gcc.gnu.org/gcc-4.4/c99status.html...

Yet I tried
int i = 3,
ii = {3},
ic = (int){3};
struct S { int i; }
s = { 3 },
sc = { (int){3} };

with my old copy (3.4) of GCC at hand (note: "compound literals" are
marked "done" in http://gcc.gnu.org/gcc-3.4/c99status.html), and I got

comp_init.c:3: error: initializer element is not constant
comp_init.c:6: error: initializer element is not constant
comp_init.c:6: error: (near initialization for `sc.i')
comp_init.c:6: warning: missing initializer
comp_init.c:6: warning: (near initialization for `sc.i')

Clearly this GCC does not like compounds litterals in initializers.
Of course GCC might have been improved since 2004.

I also spotted http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30006 which
appeared to me related; yet it is open since 2006 with nobody assigned,
and while the original reporter as well as the first person which
confirmed the report seem to think compound literals should be OK as
initializers, then the discussion moved away (about designators in
structure initializers and the warnings it caused) and since it only
causes warnings, it seems to be left as it.


Best regards
Antoine

James Kuyper

unread,
Jan 4, 2010, 8:48:26 AM1/4/10
to
Antoine Leca wrote:
> James Kuyper wrote:
...

>> Antoine Leca wrote:
>>> James Kuyper wrote:
>>>> The value of an object (named or unnamed) is not a constant expression,
>>>> not even if that object is created by a compound literal.
>>> This is where I have a doubt.
> <big snip of irrelevant part>
>> What I was saying is that
>>
>> float _Complex fc0 = (float _Complex){3.0};
>>
>> is equivalent to
>>
>> float _Complex temp = 3.0;
>> float _Complex fc0 = temp;
>>
>> and would therefore be disallowed for the same reason: 'temp' doesn't
>> qualify as any of the permitted types of operands is 6.6p8. It isn't any
>> type of constant, nor is it a sizeof expression.
>>
>> However, the expression 5 + 3 * 2 also has an operand (3*2) which
>> doesn't qualify, yet I would be surprised by any compiler which refused
>> to accept 5 + 3 * 2 as an arithmetic constant expression. I think it is
>> widely understood, and possibly stated somewhere in a DR, that the
>> restrictions on operands in 6.6p8 apply only to operands which do not
>> have sub-expressions - or possibly I'm just missing something that
>> allows 3*2.
>
> I do not follow you here. 6.6 certainly allows for sub-operations?!

6.6p8 Says that all operands of an arithmetic constant expression must
be either constants or sizeof expressions. This seems to quite clearly
exclude all operands which are expressions with sub-expressions; such
expressions may be constant expressions, but they are not constants, as
that term is defined in 6.4.4p1. The very next sentence of 6.6p8 imposes
requirements on cast operations in arithmetic constant expressions,
despite the fact that the first sentence would seem to exclude cast
expressions, so this was clearly not the intent. My best guess is that
the intent would be best reflected by correcting "have operands" with
"contain primary expressions". That would prohibit 'temp' while allowing
(float _Complex){3.0}.

...


>> However, gcc (when put into the most nearly C99-conforming mode that
>> it has) disagrees, so I could be mistaken.
>
> Perhaps a bug; is it time to start the discussion there, with more
> people involved?

I don't have time to monitor the appropriate gcc forum; but feel free to
quote my comments if you choose to take the discussion there.

Fred J. Tydeman

unread,
Jan 4, 2010, 11:09:50 AM1/4/10
to
On Mon, 4 Jan 2010 13:48:26 UTC, James Kuyper <james...@verizon.net> wrote:

> >> However, the expression 5 + 3 * 2 also has an operand (3*2) which
> >> doesn't qualify, yet I would be surprised by any compiler which refused
> >> to accept 5 + 3 * 2 as an arithmetic constant expression. I think it is
> >> widely understood, and possibly stated somewhere in a DR, that the
> >> restrictions on operands in 6.6p8 apply only to operands which do not
> >> have sub-expressions - or possibly I'm just missing something that
> >> allows 3*2.
> >
> > I do not follow you here. 6.6 certainly allows for sub-operations?!
>
> 6.6p8 Says that all operands of an arithmetic constant expression must
> be either constants or sizeof expressions. This seems to quite clearly
> exclude all operands which are expressions with sub-expressions; such
> expressions may be constant expressions, but they are not constants, as
> that term is defined in 6.4.4p1. The very next sentence of 6.6p8 imposes
> requirements on cast operations in arithmetic constant expressions,
> despite the fact that the first sentence would seem to exclude cast
> expressions, so this was clearly not the intent. My best guess is that
> the intent would be best reflected by correcting "have operands" with
> "contain primary expressions". That would prohibit 'temp' while allowing
> (float _Complex){3.0}.

6.6#5 talks about expressions.
6.5#1 defines expressions.

However, I agree with you that it would be clearer if "have operands"
were changed to "contain primary expressions"

jameskuyper

unread,
Jan 4, 2010, 12:37:07 PM1/4/10
to
Fred J. Tydeman wrote:
> On Mon, 4 Jan 2010 13:48:26 UTC, James Kuyper <james...@verizon.net> wrote:
>
> > >> However, the expression 5 + 3 * 2 also has an operand (3*2) which
> > >> doesn't qualify, yet I would be surprised by any compiler which refused
> > >> to accept 5 + 3 * 2 as an arithmetic constant expression. I think it is
> > >> widely understood, and possibly stated somewhere in a DR, that the
> > >> restrictions on operands in 6.6p8 apply only to operands which do not
> > >> have sub-expressions - or possibly I'm just missing something that
> > >> allows 3*2.
> > >
> > > I do not follow you here. 6.6 certainly allows for sub-operations?!
> >
> > 6.6p8 Says that all operands of an arithmetic constant expression must
> > be either constants or sizeof expressions. This seems to quite clearly
> > exclude all operands which are expressions with sub-expressions; such
> > expressions may be constant expressions, but they are not constants, as
> > that term is defined in 6.4.4p1. The very next sentence of 6.6p8 imposes
> > requirements on cast operations in arithmetic constant expressions,
> > despite the fact that the first sentence would seem to exclude cast
> > expressions, so this was clearly not the intent. My best guess is that
> > the intent would be best reflected by correcting "have operands" with

Correction: with => to.

> > "contain primary expressions". That would prohibit 'temp' while allowing
> > (float _Complex){3.0}.
>
> 6.6#5 talks about expressions.
> 6.5#1 defines expressions.

That is quite true; but if you believe that what those clauses say
about expressions is relevant to resolving this issue, it would be
helpful if you would explain how.

Note that 6.5p1's definition of "expression" is also defective. It can
be derived from clauses 6.5.1 through 6.5.17, that a stand-alone
constant such as 42 is a grammatically valid expression. By stand-
alone, I meant one that occurs in a context where it is not itself an
operand of any operator, such as in an initialization list or as a
dimension of an array. Since it is not an operand, and is certainly
not an operator, it fails to meet 6.5p1's definition of an expression.
It's pretty clear from examples throughout the rest of the standard
that stand-alone constants are intended to qualify as expressions, but
6.5p1's definition does not correctly express that intent.

Richard Bos

unread,
Jan 4, 2010, 3:41:44 PM1/4/10
to
jacob navia <ja...@spamsink.net> wrote:

> The only sensible solution is to standardize existing practice
> and have complex numbers use the "i" suffix for the imaginary
> part.
>
> float _Complex m = 2.3+4.6i;
>
> This
>
> 1) Eliminates the need to include <complex.h> to be able
> to recognize a complex constant. Because now if you write
> <file foo.c>
> double _Complex b = 1.2+4.5*I;
> <end of file>
> You get "undefined identifier 'I'". Not very good.
>
> 2) All the problems and ambiguities disappear. New constants
> are needed though: NAN_I INFINITY_I, that could be defined
> as NAN*1.0i and INFINITY*1.0i
>
> I think this would be the simplest and most intuitive solution.

Stop the presses! I agree completely with a post by jacob navia...

It also fits very nicely with the existing suffixes for long and
unsigned numbers, and does not break any currently legal constructs that
I can think of.

Richard

Mark Dickinson

unread,
Jan 5, 2010, 5:40:14 AM1/5/10
to
On Jan 4, 8:41 pm, ralt...@xs4all.nl (Richard Bos) wrote:
> jacob navia <ja...@spamsink.net> wrote:
> > The only sensible solution is to standardize existing practice
> > and have complex numbers use the "i" suffix for the imaginary
> > part.
>
> > float _Complex m = 2.3+4.6i;
> > [rationale snipped]

> > I think this would be the simplest and most intuitive solution.
>
> Stop the presses! I agree completely with a post by jacob navia...
>
> It also fits very nicely with the existing suffixes for long and
> unsigned numbers, and does not break any currently legal constructs that
> I can think of.

It *is* a nice idea, but I don't see how it could be made to work
completely: with IEEE 754 binary64 doubles and the usual round-half-to-
even rounding mode, and assuming that e.g., 2.75i should be
interpreted as a complex number with real part 0.0 and imaginary part
2.75, it seems to me that x + yi would still fail to give a complex
number with real part x and imaginary part y in one important case,
namely when x is negative zero. (I'm still assuming no implementation
support for imaginary types here.) I'm not sure whether I dare
mention this in this newsgroup, but you can see this problem in
Python, which uses a similar scheme for imaginary literals (which,
despite the name, actually have complex type):

[Python 2.7a1]
>>> -0.0 + 3.4j # real part of result is 0.0, not -0.0
3.4j
>>> complex(-0.0, 3.4) # this is the only sensible way to get -0.0 into the real part
(-0+3.4j)

--
Mark

Antoine Leca

unread,
Jan 5, 2010, 6:21:20 AM1/5/10
to
Jacob Navia wrote:
> The only sensible solution is to standardize existing practice
> and have complex numbers use the "i" suffix for the imaginary
> part.
>
> float _Complex m = 2.3+4.6i;

Unfortunately for this otherwise good idea, a major vendor has already
gone its own way and "used" (some may say "wasted") this suffix in a
somewhat incompatible way.

The idea would still work if the imaginary constant is constrained to
*not* be an integer-constant (ie only a flotting-constant), but I guess
that if we end as
float _Complex fcOK = 2+4.i; // accepted
float _Complex fcKO = 2+4i; // syntax error

people will be somewhat angry.


The next idea could be to use j instead of i. There are precedent for
that notation (besides GCC, I mean), however I do not remember right now
if it is software practice or restricted to engineering (electricity).
Of course it results a lot less sexy.


Antoine

James Kuyper

unread,
Jan 5, 2010, 7:50:00 AM1/5/10
to
Antoine Leca wrote:
> Jacob Navia wrote:
>> The only sensible solution is to standardize existing practice
>> and have complex numbers use the "i" suffix for the imaginary
>> part.
>>
>> float _Complex m = 2.3+4.6i;
>
> Unfortunately for this otherwise good idea, a major vendor has already
> gone its own way and "used" (some may say "wasted") this suffix in a
> somewhat incompatible way.

How major a vendor? I can understand why you might not want to name
names. However, if you're going to argue against an idea based upon
conflict with a widely used extension, it's important to support your
argument that we have some idea of how widely used that extension is. A
survey of code bases would be ideal, but simply knowing who the vendor
is would help form a rough idea of how important it is to avoid such a
conflict.

As a side note, what is the conflicting use to which they put this syntax?

jacob navia

unread,
Jan 5, 2010, 8:59:42 AM1/5/10
to
Antoine Leca a �crit :

> Jacob Navia wrote:
>> The only sensible solution is to standardize existing practice
>> and have complex numbers use the "i" suffix for the imaginary
>> part.
>>
>> float _Complex m = 2.3+4.6i;
>
> Unfortunately for this otherwise good idea, a major vendor has already
> gone its own way and "used" (some may say "wasted") this suffix in a
> somewhat incompatible way.
>

You mean Microsoft corp and I64?

That is easy to distinguish... Really. In lcc-win I support both.

> The idea would still work if the imaginary constant is constrained to
> *not* be an integer-constant (ie only a flotting-constant), but I guess
> that if we end as
> float _Complex fcOK = 2+4.i; // accepted
> float _Complex fcKO = 2+4i; // syntax error
>
> people will be somewhat angry.
>

No, that would not work.

Kaz Kylheku

unread,
Jan 5, 2010, 12:22:49 PM1/5/10
to
On 2010-01-05, Antoine Leca <ro...@localhost.invalid> wrote:
> Jacob Navia wrote:
>> The only sensible solution is to standardize existing practice
>> and have complex numbers use the "i" suffix for the imaginary
>> part.
>>
>> float _Complex m = 2.3+4.6i;
>
> Unfortunately for this otherwise good idea, a major vendor has already
> gone its own way and "used" (some may say "wasted") this suffix in a
> somewhat incompatible way.

Not a problem. Such reasoning didn't prevent, oh, C99 inline and
variable length arrays.

Antoine Leca

unread,
Jan 5, 2010, 12:28:50 PM1/5/10
to
James Kuyper wrote:
> Antoine Leca wrote:
>>> float _Complex m = 2.3+4.6i;
>>
>> Unfortunately for this otherwise good idea, a major vendor has already
>> gone its own way and "used" (some may say "wasted") this suffix in a
>> somewhat incompatible way.
>
> How major a vendor?

Sorry for the ellipse, I did not want to open the Pandora box.

I meant Microsoft and the Visual C++ compiler, which since about 1995
has i64, I64 (also i128, I128, and I think also i256 and I256) as
suffixes to describe the number of bits in an integer constant.


> A survey of code bases

Well, the /user/ base is pretty large (since here we should also count
C++ users as well, as well as the quirk-for-quirk clones).

Of course, since this is a minor feature of that compiler, the use of
the feature is less than common, so the real code base is probably
pretty small. Yet I fail to see how the real code base may be important,
I feel it is the size of the user base which will matter, won't it?


> As a side note, what is the conflicting use to which they put this syntax?

I do not know if the syntaxes /conflict/ (also Jacob says they do not);
I just believe the meanings are different, so it might very well confuse
the code writers. I am at difficulty to actually find a problem, but
I believe mixing two different things is likely to have bad results.

The most problematic I found so far is the following minor annoyance:
when she is porting a code from VC to another compiler, and suddenly
gets error messages speaking about "complex numbers not allowed there"
when the original code was purely integer handling...


On the other hand, perhaps this whole discussion had already taken place
at GCC lists, when they started implementing this extension?


Antoine

Keith Thompson

unread,
Jan 5, 2010, 12:55:28 PM1/5/10
to
Antoine Leca <ro...@localhost.invalid> writes:
> James Kuyper wrote:
>> Antoine Leca wrote:
>>>> float _Complex m = 2.3+4.6i;
>>>
>>> Unfortunately for this otherwise good idea, a major vendor has already
>>> gone its own way and "used" (some may say "wasted") this suffix in a
>>> somewhat incompatible way.
>>
>> How major a vendor?
>
> Sorry for the ellipse, I did not want to open the Pandora box.
>
> I meant Microsoft and the Visual C++ compiler, which since about 1995
> has i64, I64 (also i128, I128, and I think also i256 and I256) as
> suffixes to describe the number of bits in an integer constant.

I haven't used this feature of VC++ (or VC++ itself for that matter),
but it doesn't look incompatible. From your description, the VC++
'i' or 'I' suffix is always immediately followed by a digit; the
proposed 'i' suffix for imaginary numbers would never be immediately
followed by a digit.

[...]

> I do not know if the syntaxes /conflict/ (also Jacob says they do not);
> I just believe the meanings are different, so it might very well confuse
> the code writers. I am at difficulty to actually find a problem, but
> I believe mixing two different things is likely to have bad results.

I don't think it's a problem.

> The most problematic I found so far is the following minor annoyance:
> when she is porting a code from VC to another compiler, and suddenly
> gets error messages speaking about "complex numbers not allowed there"
> when the original code was purely integer handling...

It's possible that a compiler that supports the 'i' imaginary suffix
might interpret 42.0i64 as an incorrect imaginary literal, and produce
a confusing error message. But gcc, for example, just says
error: invalid suffix "i64" on floating constant

In any case, the error message, even if it's confusing, should
pinpoint the line containing the unrecognized literal.

[...]

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Richard Bos

unread,
Jan 11, 2010, 1:14:53 PM1/11/10
to
Mark Dickinson <dick...@gmail.com> wrote:

> On Jan 4, 8:41=A0pm, ralt...@xs4all.nl (Richard Bos) wrote:
> > jacob navia <ja...@spamsink.net> wrote:
> > > The only sensible solution is to standardize existing practice
> > > and have complex numbers use the "i" suffix for the imaginary
> > > part.
> >

> > > float _Complex m =3D 2.3+4.6i;


> > > [rationale snipped]
> > > I think this would be the simplest and most intuitive solution.
> >
> > Stop the presses! I agree completely with a post by jacob navia...
> >
> > It also fits very nicely with the existing suffixes for long and
> > unsigned numbers, and does not break any currently legal constructs that
> > I can think of.
>
> It *is* a nice idea, but I don't see how it could be made to work
> completely: with IEEE 754 binary64 doubles and the usual round-half-to-
> even rounding mode, and assuming that e.g., 2.75i should be
> interpreted as a complex number with real part 0.0 and imaginary part
> 2.75, it seems to me that x + yi would still fail to give a complex
> number with real part x and imaginary part y in one important case,
> namely when x is negative zero. (I'm still assuming no implementation
> support for imaginary types here.)

Ah, now, there's the rub. We already _have_ support for imaginary types.
I'm not suggesting inventing a completely new kind of imaginary number
system unrelated to what we have now. I am suggesting, and AFAICT so was
jacob, that instead of the current kludge we have now, we could build
imaginary numbers - however non-IEEE as might be necessary on some
implementations - using an i suffix where we now have to #include a
header and use *I.

IOW, what I was thinking of might have rounding or conversion problems
on some implementations, but no _more_ than what we already have in C99.
It would not be a new system with new problems, it would merely be a
less ugly way of expressing the system we have now, including only
problems that we have now as well.

Richard

Mark Dickinson

unread,
Jan 11, 2010, 3:28:37 PM1/11/10
to
On Jan 11, 6:14 pm, ralt...@xs4all.nl (Richard Bos) wrote:
> Ah, now, there's the rub. We already _have_ support for imaginary types.

Which 'we'?! I'm still using gcc, which doesn't appear to support
them. I don't have much compiler experience beyond gcc: are there
other mainstream compilers that do support imaginary types?

> I'm not suggesting inventing a completely new kind of imaginary number
> system unrelated to what we have now. I am suggesting, and AFAICT so was
> jacob, that instead of the current kludge we have now, we could build
> imaginary numbers - however non-IEEE as might be necessary on some
> implementations - using an i suffix where we now have to #include a
> header and use *I.
>

> [...]

Ah, okay. I'd (mis?)understood Jacob's proposal as a solution to the
problem described in n1431, and was pointing out that it doesn't
completely solve that problem, thanks to the issues with negative
zeros.

As you say, the idea of adding an 'i'-suffixed imaginary literal is
orthogonal to this.

--
Mark

Tim Rentsch

unread,
Feb 1, 2010, 4:12:17 AM2/1/10
to
Antoine Leca <ro...@localhost.invalid> writes:

[snip]


> So please let's focus on (otherwise valid) compound litterals to be used
> as initializers.
>

> [snip incidental digression]


>
> I spotted two discussions in early 2008 this about at
> http://osdir.com/ml/comp.compilers.clang.devel/2008-01/ available
> through news://news.gmane.org/gmane.comp.compilers.clang.devel,
> starting at <news:43A3FB85-F8DB-43D8...@apple.com> and
> <news:f5aa3e9b0801250929s48f...@mail.gmail.com>; the
> latter contains "Per the standard, a compound literal is not a constant
> expression, period." Pretty much to the point, I would say. Yet I prefer
> demonstrations to assertions. ;-)
>
>
> Do not take me wrong: if "allowed" is the correct reading, I think this
> is a bug in the Standard, since apparently many knowledgeable people are
> thinking compound literals should *not* be allowed as constants, and I
> failed to see many (knowledgeable people, that is) in the other camp; so
> the current Standard text would violate the principe of least surprise.

Sorry for the late reply here...

As I read the Standard, a more accurate statement is this: Compound
literals _may_ be accepted in constant expressions (including
integer constant expressions), but are not _required_ to be accepted
in constant expressions. This last point may be debatable for
things like, eg, (int){5}, on the basis of some highly technical
argument, but as a general rule it seems clear that the Standard
does not expect that compound literals to be required forms of
constant expressions.

They are allowed by virtue of 6.6p10. Also, since allowing them
doesn't violate any constraint, I believe it's legal to accept them
without issuing a diagnostic. (Of course sensible compiler writers
will provide an option to have such things flagged, but I don't
think the Standard requires that for conformance.)

Keith Thompson

unread,
Feb 1, 2010, 3:31:24 PM2/1/10
to

I disagree. I don't think that 6.6p10, "An implementation may accept
other forms of constant expressions", is necessary here.

Consider:

struct foo { int x; int y; };
int main(void)
{
(struct foo){ .x = 10, .y = 20 };
return 0;
}

"(struct foo){ .x = 10, .y = 20 }" is a compound literal. I assert
that it is a constant expression.

Syntactically, the grammar is simply:

constant-expression:
conditional-expression

(Using "conditional-expression" rather than just "expression" excludes
assignments and comma operators at the top level.)

The constraints on a constant expression are:

Constant expressions shall not contain assignment, increment,
decrement, function-call, or comma operators, except when they
are contained within a subexpression that is not evaluated.

Each constant expression shall evaluate to a constant that is
in the range of representable values for its type.

The compound literal above violates none of these constraints.
The idea of the "range" of representable values for a struct
type is a bit iffy, but it's no worse than for pointer types.

C99 6.6 defines constant expressions by starting with expressions
and specifying features that disqualify an expression from being a
constant expression. Compound literals have none of those features.

Note that gcc doesn't seem to agree with this. Given:

struct foo { int x; int y; };
struct foo obj = (struct foo) { .x = 10, .y = 20 };

it complains:

c.c:2: error: initializer element is not constant

(C99 6.7.8p4: "All the expressions in an initializer for an object


that has static storage duration shall be constant expressions or

string literals.")

Tim Rentsch

unread,
Feb 3, 2010, 1:55:31 PM2/3/10
to
Keith Thompson <ks...@mib.org> writes:

> Tim Rentsch <t...@alumni.caltech.edu> writes:
>> Antoine Leca <ro...@localhost.invalid> writes:
>>
>> [snip]
>>> So please let's focus on (otherwise valid) compound litterals to be used
>>> as initializers.

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Please note the above.

Ignoring for a moment whether 6.6p10 is necessary, we agree that
it is sufficient, yes?


> Consider:
>
> struct foo { int x; int y; };
> int main(void)
> {
> (struct foo){ .x = 10, .y = 20 };
> return 0;
> }
>
> "(struct foo){ .x = 10, .y = 20 }" is a compound literal. I assert
> that it is a constant expression.

I don't think it is. But even if it is, it certainly doesn't
qualify (absent 6.6p10) as a constant expression that could be
used in an initializer, because of 6.6p7.


> Syntactically, the grammar is simply:
>
> constant-expression:
> conditional-expression
>
> (Using "conditional-expression" rather than just "expression" excludes
> assignments and comma operators at the top level.)
>
> The constraints on a constant expression are:
>
> Constant expressions shall not contain assignment, increment,
> decrement, function-call, or comma operators, except when they
> are contained within a subexpression that is not evaluated.
>
> Each constant expression shall evaluate to a constant that is
> in the range of representable values for its type.
>
> The compound literal above violates none of these constraints.
> The idea of the "range" of representable values for a struct
> type is a bit iffy, but it's no worse than for pointer types.
>
> C99 6.6 defines constant expressions by starting with expressions
> and specifying features that disqualify an expression from being a
> constant expression. Compound literals have none of those features.

That's all true but it doesn't include the requirements of 6.6p7.
These requirements contain a "shall" restriction that the compound
literal "(struct foo){ .x = 10, .y = 20 }" violates.

An argument could be made that the term 'constant expression' is
defined solely by 6.6p1, 6.6p2, and 6.6p3, and that 6.6p7 is merely
adding additional requirements for "conditional expressions" when
used in initializers. Personally, I think that interpretation is
wrong; the provisions of 6.6p7 are meant to apply to the term
'constant expression' itself, not just in the context of when a
syntactically valid expression is used in an initializer. In any
case these provisions certainly apply in the context that my
earlier remarks were made, which context is "compound literals to
be used as initializers."


> Note that gcc doesn't seem to agree with this. Given:
>
> struct foo { int x; int y; };
> struct foo obj = (struct foo) { .x = 10, .y = 20 };
>
> it complains:
>
> c.c:2: error: initializer element is not constant
>
> (C99 6.7.8p4: "All the expressions in an initializer for an object
> that has static storage duration shall be constant expressions or
> string literals.")

Gcc is right to complain here because the initializer here must
satisfy the provisions of 6.6p7, and the proposed initializer
violates the "shall" restriction contained therein.

Keith Thompson

unread,
Feb 3, 2010, 2:46:15 PM2/3/10
to
Tim Rentsch <t...@alumni.caltech.edu> writes:
> Keith Thompson <ks...@mib.org> writes:
>> Tim Rentsch <t...@alumni.caltech.edu> writes:
>>> Antoine Leca <ro...@localhost.invalid> writes:
>>>
>>> [snip]
>>>> So please let's focus on (otherwise valid) compound litterals to be used
>>>> as initializers.
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> Please note the above.
[...]

>>> They are allowed by virtue of 6.6p10. Also, since allowing them
>>> doesn't violate any constraint, I believe it's legal to accept them
>>> without issuing a diagnostic. (Of course sensible compiler writers
>>> will provide an option to have such things flagged, but I don't
>>> think the Standard requires that for conformance.)
>>
>> I disagree. I don't think that 6.6p10, "An implementation may accept
>> other forms of constant expressions", is necessary here.
>
> Ignoring for a moment whether 6.6p10 is necessary, we agree that
> it is sufficient, yes?

It's sufficient in that it allows an implementation to accept it.
My claim (which I'll partially withdraw in a moment) was that all
implementations are *required* to accept it.

>
>> Consider:
>>
>> struct foo { int x; int y; };
>> int main(void)
>> {
>> (struct foo){ .x = 10, .y = 20 };
>> return 0;
>> }
>>
>> "(struct foo){ .x = 10, .y = 20 }" is a compound literal. I assert
>> that it is a constant expression.
>
> I don't think it is. But even if it is, it certainly doesn't
> qualify (absent 6.6p10) as a constant expression that could be
> used in an initializer, because of 6.6p7.

How does it not qualify as a constant expression? (Though there may
not be any cases where it matters whether it's a constant expression
or not.)

As for using it in an initializer, you're right, I missed that.

Here's what 6.6p7 says:

More latitude is permitted for constant expressions in
initializers. Such a constant expression shall be, or evaluate
to, one of the following:

-- an arithmetic constant expression,
-- a null pointer constant,
-- an address constant, or
-- an address constant for an object type plus or minus an integer
constant expression.

What I find extremely odd, though, is that this requirement appears in
the Semantics section, not in the Constraints section. The violation
of a "shall" outside a constraint implies undefined behavior.

If 6.6p7 is intended to restrict which expressions are constant
expression, then this:

struct foo obj = (struct foo){ .x = 10, .y = 20 };

is a constraint violation. But if that's the intent, it could have
been worded much more clearly. A violation of a "shall" outside a
constraint invokes undefined behavior (C99 4p2). If the authors
intended to restrict the definition of "constant expression", they
shouldn't have used the word "shall".

It also seems odd for the same expression to be a constant expression
or not depending on its context. It would have made more sense IMHO
to say that, even though it's a constant expression, using it in an
initializer is a constaint violation.

Tim Rentsch

unread,
Feb 4, 2010, 1:50:16 AM2/4/10
to
Keith Thompson <ks...@mib.org> writes:

I believe it doesn't qualify as a constant expression because
the provisions of 6.6p7 are meant to be part of the definition
of "constant expression", not just to apply in the context of
initializers.


> As for using it in an initializer, you're right, I missed that.
>
> Here's what 6.6p7 says:
>
> More latitude is permitted for constant expressions in
> initializers. Such a constant expression shall be, or evaluate
> to, one of the following:
>
> -- an arithmetic constant expression,
> -- a null pointer constant,
> -- an address constant, or
> -- an address constant for an object type plus or minus an integer
> constant expression.
>
> What I find extremely odd, though, is that this requirement appears in
> the Semantics section, not in the Constraints section. The violation
> of a "shall" outside a constraint implies undefined behavior.

Consider the parallel with "integer constant expression". Its
definition, and "shall" requirements, appear in 6.6p6 (also the
Semantics section). Clearly these requirements are meant to be
part of the definition for "integer constant expression". So
it seems reasonable that the requirements in 6.6p7 are meant to
be part of the definition of "constant expression". Right?


> If 6.6p7 is intended to restrict which expressions are constant
> expression, then this:
>
> struct foo obj = (struct foo){ .x = 10, .y = 20 };
>
> is a constraint violation. But if that's the intent, it could have
> been worded much more clearly. A violation of a "shall" outside a
> constraint invokes undefined behavior (C99 4p2). If the authors
> intended to restrict the definition of "constant expression", they
> shouldn't have used the word "shall".

In fact I believe the circumstance of being plain undefined behavior
(as opposed to being a constraint violation) was deliberate. And it
was done this way precisely so that the additional forms allowed by
6.6p10 could be accepted without having to generate diagnostics.


> It also seems odd for the same expression to be a constant expression
> or not depending on its context.

Yes, that's part of the reason that I think 6.6p7 is part of the
definition of "constant expression", independent of whether the
expression in question is used in an initializer or not.


> It would have made more sense IMHO
> to say that, even though it's a constant expression, using it in an
> initializer is a constaint violation.

Constant expressions are used basically only in (some) initializers
(except there a couple of restricted forms of CE used in other places,
such as array indices or preprocessor control expressions). Wouldn't
it seem rather strange to define a term "constant expression" that is
applicable only in a certain context, and then say, "Oh, in that
context, only some constant expressions are allowed"? To me it makes
more sense to give a definition that applies in those places where the
term is used, because in other places whether or not something is a
constant expression doesn't matter (again, with the understanding that
there are a few places where more specialized forms of CE are
required).

0 new messages