# What is a sequence point?

Discussion in 'C Programming' started by Deniz Bahar, Feb 11, 2005.

1. ### Deniz BaharGuest

I know the basic definition of a sequence point (point where all side
statement:

"Between the previous and next sequence point an object shall have its
stored value modified at most once by the evaluation of an expression.
Furthermore, the prior value shall be accessed only to determine the
value to be stored."

Can someone give me examples of expressions that "barely" break this
rule (the type a newcomer might trip over)?

If you are between sequence points, then what does that second sentence
mean "prior value"?

Deniz Bahar, Feb 11, 2005

2. ### Randy HowardGuest

In article <>,
says...
> I know the basic definition of a sequence point (point where all side
> statement:
>
> "Between the previous and next sequence point an object shall have its
> stored value modified at most once by the evaluation of an expression.
> Furthermore, the prior value shall be accessed only to determine the
> value to be stored."
>
> Can someone give me examples of expressions that "barely" break this
> rule (the type a newcomer might trip over)?
>
> If you are between sequence points, then what does that second sentence
> mean "prior value"?

Specifically,
http://www.eskimo.com/~scs/C-faq/q3.8.html

Also related:
http://www.eskimo.com/~scs/C-faq/q3.1.html
http://www.eskimo.com/~scs/C-faq/q3.2.html
http://www.eskimo.com/~scs/C-faq/q3.3.html
http://www.eskimo.com/~scs/C-faq/q3.9.html

Then read all of it again.

--
"Making it hard to do stupid things often makes it hard
to do smart ones too." -- Andrew Koenig

Randy Howard, Feb 11, 2005

3. ### Deniz BaharGuest

Randy Howard wrote:
> >
> > If you are between sequence points, then what does that second

sentence
> > mean "prior value"?

>
> Specifically,
> http://www.eskimo.com/~scs/C-faq/q3.8.html
>
> Also related:
> http://www.eskimo.com/~scs/C-faq/q3.1.html
> http://www.eskimo.com/~scs/C-faq/q3.2.html
> http://www.eskimo.com/~scs/C-faq/q3.3.html
> http://www.eskimo.com/~scs/C-faq/q3.9.html
>
> Then, read the entire FAQ.
>
> Then read all of it again.
>

I read the FAQ before my original post. It was the FAQ that actually
tickled my mind and made me wonder if I was just lucky all this time
when I was using side effects in expressions.

This sentence from the FAQ really confused me:

"The second sentence can be difficult to understand. It says that if an
object is written to within a full expression, any and all accesses to
it within the same expression must be for the purposes of computing the
value to be written. This rule effectively constrains legal expressions
to those in which the accesses demonstrably precede the modification."

More confused about the FAQ's explanation of the sentence from the
standard than the standard itself. I'm all around confused about side
effect and sequence points :_(

Deniz Bahar, Feb 11, 2005
4. ### Randy HowardGuest

In article <>,
says...
>
> Randy Howard wrote:
> > >
> > > If you are between sequence points, then what does that second

> sentence
> > > mean "prior value"?

> >
> > Specifically,
> > http://www.eskimo.com/~scs/C-faq/q3.8.html
> >
> > Also related:
> > http://www.eskimo.com/~scs/C-faq/q3.1.html
> > http://www.eskimo.com/~scs/C-faq/q3.2.html
> > http://www.eskimo.com/~scs/C-faq/q3.3.html
> > http://www.eskimo.com/~scs/C-faq/q3.9.html
> >
> > Then, read the entire FAQ.
> >
> > Then read all of it again.
> >

>
> I read the FAQ before my original post. It was the FAQ that actually
> tickled my mind and made me wonder if I was just lucky all this time
> when I was using side effects in expressions.

Ok, well, the links after the first one contain specific examples. I
was hoping that one or more of them would turn the lightbulb on for
you because I usually find that examples can be helpful when the legalese
gets overwhelming.

In particular, 3.2 has a more lengthy explanation, and a common example
as well. It seems to explain it pretty well to me, so if that doesn't do
it for you, maybe somebody else can provide a better explanation.

--
"Making it hard to do stupid things often makes it hard
to do smart ones too." -- Andrew Koenig

Randy Howard, Feb 11, 2005
5. ### peteGuest

Deniz Bahar wrote:
>
> I know the basic definition of a sequence point (point where all side
> statement:
>
> "Between the previous and next sequence point an object shall have its
> stored value modified at most once by the evaluation of an expression.
> Furthermore, the prior value shall be accessed only to determine the
> value to be stored."
>
> Can someone give me examples of expressions that "barely" break this
> rule (the type a newcomer might trip over)?
>
> If you are between sequence points,
> then what does that second sentence
> mean "prior value"?

(p = p -> next = q)

The above doesn't specify the order of assignment and is undefined.
It could be either (p = q, p -> next = q) or (p -> next = q, p = q).

(i = x++)
The above is being debated on comp.std.c
The i in x++ is evaluated only once, but for two reasons.
It's evaluated to determine the value of the right operand of
the assignment operator, but also to determine the address of
the lvalue of the increment operator.

--
pete

pete, Feb 11, 2005
6. ### Richard BosGuest

"Deniz Bahar" <> wrote:

> I know the basic definition of a sequence point (point where all side
> statement:
>
> "Between the previous and next sequence point an object shall have its
> stored value modified at most once by the evaluation of an expression.
> Furthermore, the prior value shall be accessed only to determine the
> value to be stored."
>
> Can someone give me examples of expressions that "barely" break this
> rule (the type a newcomer might trip over)?
>
> If you are between sequence points, then what does that second sentence
> mean "prior value"?

A sequence point is a point in the execution of a program at which all
side effects (that is, all assignments, file output and volatile
accesses) must have been completed. Examples are at the end of a
complete expression, just before a function call, and at the logical,
comma and conditional operators.
The compiler is allowed to "save up" or mix side effects between two
adjacent sequence points, for example if that results in more efficient
code. However, _at_ a sequence point, all side effects must be complete.

This is useful; it allows both

int a,b;
char x[10],y[10];

...
x[a++]=y[b++];

to be compiled efficiently (possibly with both increments being done in
parallel), _and_

if (valid_index(a) && array[a]>cutoff)

to be compiled safely, that is, without the compiler trying to be
efficient by computing array[a] before we're sure a is valid.

It also means (and here we come to your example) that

a=i++;

is invalid code, because i++ is both incremented, _and_ read for another
purpose than the increment. In the sub-expression i++, i is given a new
value; but in the sub-expression a, the _prior value_ of i, that is,
its value before the increment, is used to determine which array member
to assign to.

Richard

Richard Bos, Feb 11, 2005
7. ### Luke WuGuest

Deniz Bahar wrote:
> I know the basic definition of a sequence point (point where all side
> statement:
>
> "Between the previous and next sequence point an object shall have

its
> stored value modified at most once by the evaluation of an

expression.
> Furthermore, the prior value shall be accessed only to determine the
> value to be stored."
>

I don't know where you got that passage from, but this one from the
last C89 draft is a lot more clear:

"[If] an object is modified more than once, or is modified and accessed
other than to determine the new value, between two sequence points [,
undefined behaviour reusults]"

There are two parts to this:

1) An object can't be modified more than once between sequence points:
examples

j = i-- * i--; /* more obvious fault */

j = ++i * ++i; /* less obvious, but still breaches rule */

You might think that the pre-increments are okay because side effects
happen immediately, but it doesn't matter because the literature says
you can't modify an object more than once.

2) Between sequence points, an object can't be modified and accessed
other than to determine it's new value (trickier of the two parts of
the rule).

examples

i = i + 3; this is okay because i is modified (i = ____) and accessed
(rvalue the the left of =) only to determine the new value for the i

(i += 3) * j; this is not okay, because i is modified (i += _-__) and
accessed (rvalue of i later used to multiply with j) for a reason that
isn't to determine the new value of i.

i = (i += 3) * j; this is okay, because i is modified (i += ____) and
is accessed to determine the new value of i (left side i = _____).

a[i++]; this is not okay, because i is modified [i++] then accessed to
determine something other than the new value of i.

I hope this helps.

Luke Wu, Feb 11, 2005
8. ### Luke WuGuest

pete wrote:
> Deniz Bahar wrote:
> >
> > I know the basic definition of a sequence point (point where all

side
> > statement:
> >
> > "Between the previous and next sequence point an object shall have

its
> > stored value modified at most once by the evaluation of an

expression.
> > Furthermore, the prior value shall be accessed only to determine

the
> > value to be stored."
> >
> > Can someone give me examples of expressions that "barely" break

this
> > rule (the type a newcomer might trip over)?
> >
> > If you are between sequence points,
> > then what does that second sentence
> > mean "prior value"?

>
> (p = p -> next = q)
>
> The above doesn't specify the order of assignment and is undefined.
> It could be either (p = q, p -> next = q) or (p -> next = q, p = q).

but =assignment operators associate left to right, so it would be:

(p -> next = q, p = q)

>
>
> (i = x++)
> The above is being debated on comp.std.c
> The i in x++ is evaluated only once, but for two reasons.
> It's evaluated to determine the value of the right operand of
> the assignment operator, but also to determine the address of
> the lvalue of the increment operator.
>

this would seem to break the rule, because the postincrement is not an

Luke Wu, Feb 11, 2005
9. ### infobahnGuest

Luke Wu wrote:
>
> pete wrote:
> > (p = p -> next = q)
> >
> > The above doesn't specify the order of assignment and is undefined.
> > It could be either (p = q, p -> next = q) or (p -> next = q, p = q).

>
> but =assignment operators associate left to right, so it would be:
>
> (p -> next = q, p = q)

Wrong. Because there's no sequence point, the compiler is free to do
the evaluations in any order it likes. Associativity does not
determine the order of evaluation.

infobahn, Feb 11, 2005
10. ### Lawrence KirbyGuest

On Fri, 11 Feb 2005 08:08:44 -0800, Luke Wu wrote:

>
> Deniz Bahar wrote:
>> I know the basic definition of a sequence point (point where all side
>> statement:
>>
>> "Between the previous and next sequence point an object shall have

> its
>> stored value modified at most once by the evaluation of an

> expression.
>> Furthermore, the prior value shall be accessed only to determine the
>> value to be stored."
>>

>
>
> I don't know where you got that passage from, but this one from the
> last C89 draft is a lot more clear:

The text is that in the current standard.

> "[If] an object is modified more than once, or is modified and accessed
> other than to determine the new value, between two sequence points [,
> undefined behaviour reusults]"
>
> There are two parts to this:
>
> 1) An object can't be modified more than once between sequence points:
> examples
>
> j = i-- * i--; /* more obvious fault */
>
> j = ++i * ++i; /* less obvious, but still breaches rule */
>
> You might think that the pre-increments are okay because side effects
> happen immediately, but it doesn't matter because the literature says
> you can't modify an object more than once.
>
>
> 2) Between sequence points, an object can't be modified and accessed
> other than to determine it's new value (trickier of the two parts of
> the rule).
>
> examples
>
> i = i + 3; this is okay because i is modified (i = ____) and accessed
> (rvalue the the left of =) only to determine the new value for the i
>
> (i += 3) * j; this is not okay, because i is modified (i += _-__) and
> accessed (rvalue of i later used to multiply with j) for a reason that
> isn't to determine the new value of i.

This is fine. By your logic you couldn't use the result of an assignment
operator for anything. Perhaps this is one reason why the draft text
you cite was corrected?

> i = (i += 3) * j; this is okay, because i is modified (i += ____) and
> is accessed to determine the new value of i (left side i = _____).

i is modified twice between sequence points so this is undefined.

> a[i++]; this is not okay, because i is modified [i++] then accessed to
> determine something other than the new value of i.

Again, this is perfectly fine.

Note that neither assignment nor increment/decrement operators reread the
value of the object after it has been modified.

Lawrence

Lawrence Kirby, Feb 11, 2005
11. ### Luke WuGuest

infobahn wrote:
> Luke Wu wrote:
> >
> > pete wrote:
> > > (p = p -> next = q)
> > >
> > > The above doesn't specify the order of assignment and is

undefined.
> > > It could be either (p = q, p -> next = q) or (p -> next = q, p =

q).
> >
> > but =assignment operators associate left to right, so it would be:

meant to say right to left

> >
> > (p -> next = q, p = q)

>
> Wrong. Because there's no sequence point, the compiler is free to do
> the evaluations in any order it likes. Associativity does not
> determine the order of evaluation.

Yes, but = is a binary operator, and works on 2 operands.

So you can either have p = p->next, p->next =q OR p->next = q, p =
p->next

How can you have p = q ?? never is a single = operating on those two
operands

Luke Wu, Feb 11, 2005
12. ### G FernandesGuest

Deniz Bahar wrote:
> I know the basic definition of a sequence point (point where all side
> statement:
>
> "Between the previous and next sequence point an object shall have

its
> stored value modified at most once by the evaluation of an

expression.
> Furthermore, the prior value shall be accessed only to determine the
> value to be stored."
>
> Can someone give me examples of expressions that "barely" break this
> rule (the type a newcomer might trip over)?
>
> If you are between sequence points, then what does that second

sentence
> mean "prior value"?

Dont forget about function calls (the commas in them are not sequence
points).
A call such as this:

f(n++, n);

has undefined behavior because it violates the rule you quoted cited.
There's no sequence point between the argument expressions. The first
(left) argument modifies n. It also reads the value of n, but only to
determine the new value to be stored in n. So far, so good. However,
the second (right) argument expression reads the value of n between the
same pair of sequence points as the first argument, but not to
determine the value to be stored in n. This additional attempt to read
the value of n has undefined behavior.

G Fernandes, Feb 11, 2005
13. ### infobahnGuest

Luke Wu wrote:
>
> infobahn wrote:
> > >
> > > pete wrote:
> > > > (p = p -> next = q)

> > Because there's no sequence point, the compiler is free to do
> > the evaluations in any order it likes. Associativity does not
> > determine the order of evaluation.

>
> Yes, but = is a binary operator, and works on 2 operands.

So what? The compiler can view it this way:

"We have an expression of the form a = b = c; fine, I'll make them
all equal, so we'll set a equal to c and we'll set b equal to c",
so it could set p equal to q and then set p->next equal to q, with
the result that q->next = q;

or this way: it could set p->next to be equal to q, and then set p
to be equal to p->next, which would not affect q->next at all.
Either behaviour (and any other behaviour!) is legitimate.

infobahn, Feb 11, 2005
14. ### Luke WuGuest

infobahn wrote:
> Luke Wu wrote:
> >
> > infobahn wrote:
> > > >
> > > > pete wrote:
> > > > > (p = p -> next = q)

>
> > > Because there's no sequence point, the compiler is free to do
> > > the evaluations in any order it likes. Associativity does not
> > > determine the order of evaluation.

> >
> > Yes, but = is a binary operator, and works on 2 operands.

>
> So what? The compiler can view it this way:
>
> "We have an expression of the form a = b = c; fine, I'll make them
> all equal, so we'll set a equal to c and we'll set b equal to c",
> so it could set p equal to q and then set p->next equal to q, with
> the result that q->next = q;
>

No, the compiler views it according to the associativity rules(right to
left) as this:

(a = (b = c)) <=== right to left associativity

Consider also (all ints):

a + b + c

the value in a is equal to -b, the value in both b and c is almost
INT_MAX, so will over flow occur?

Based on your argument, overflow 'ca'n occur, because the compiler is
free to do (b + c) before adding the result to a.

In reality, overflow never occurs because we know the compiler will
consider that expression as:

((a + b) + c) <=== left to right associativity

the result will be rvalue(c), never an overflow in an intermediate step

Luke Wu, Feb 11, 2005
15. ### Luke WuGuest

G Fernandes wrote:
> Deniz Bahar wrote:
> > I know the basic definition of a sequence point (point where all

side
> > statement:
> >
> > "Between the previous and next sequence point an object shall have

> its
> > stored value modified at most once by the evaluation of an

> expression.
> > Furthermore, the prior value shall be accessed only to determine

the
> > value to be stored."
> >
> > Can someone give me examples of expressions that "barely" break

this
> > rule (the type a newcomer might trip over)?
> >
> > If you are between sequence points, then what does that second

> sentence
> > mean "prior value"?

>
> Dont forget about function calls (the commas in them are not sequence
> points).
> A call such as this:
>
> f(n++, n);
>
> has undefined behavior because it violates the rule you quoted cited.
> There's no sequence point between the argument expressions. The first
> (left) argument modifies n. It also reads the value of n, but only to
> determine the new value to be stored in n. So far, so good. However,
> the second (right) argument expression reads the value of n between

the
> same pair of sequence points as the first argument, but not to
> determine the value to be stored in n. This additional attempt to

> the value of n has undefined behavior.

"It also reads the value of n, but only to determine the new value to
be stored in n." No it doesn't, the first argument reads the value of n
to be sent to the function, not to be stored in n.

Luke Wu, Feb 11, 2005
16. ### Mark McIntyreGuest

On 11 Feb 2005 12:55:34 -0800, in comp.lang.c , "Luke Wu"
<> wrote:

>
>infobahn wrote:

>> So what? The compiler can view it this way:
>>
>> "We have an expression of the form a = b = c; fine, I'll make them
>> all equal, so we'll set a equal to c and we'll set b equal to c",
>> so it could set p equal to q and then set p->next equal to q, with
>> the result that q->next = q;
>>

>No, the compiler views it according to the associativity rules(right to
>left) as this:
>
>(a = (b = c)) <=== right to left associativity

The standard discusses this type of problem. In 5.1.2.3, it shows examples
and notes that in general you cannot assume the normal mathematical laws of
associativity to be applicable.

--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>

Mark McIntyre, Feb 11, 2005
17. ### Mark McIntyreGuest

On 11 Feb 2005 13:00:23 -0800, in comp.lang.c , "Luke Wu"
<> wrote:

>>
>> f(n++, n);
>>
>> has undefined behavior because it violates the rule you quoted cited.
>> There's no sequence point between the argument expressions. The first
>> (left) argument modifies n. It also reads the value of n, but only to
>> determine the new value to be stored in n. So far, so good. However,
>> the second (right) argument expression reads the value of n between the
>> same pair of sequence points as the first argument, but not to
>> determine the value to be stored in n. This additional attempt to read
>> the value of n has undefined behavior.

>
>"It also reads the value of n, but only to determine the new value to
>be stored in n." No it doesn't, the first argument reads the value of n
>to be sent to the function, not to be stored in n.

It does both.

For the first argument n is evaluated, and stored for passing to f. n is
also incremented, and stored back into n.

The second argument evaluates n and stores it for passing to f.

The order in which the two arguments are evaluated is undefined. The timing
of the increment-and-store-back is undefined. Its possible for the
increment to happen before or after the 2nd argument is evaluated. Or
simultaneously.

--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>

Mark McIntyre, Feb 11, 2005
18. ### Dave VanderviesGuest

In article <>,
Luke Wu <> wrote:

>No, the compiler views it according to the associativity rules(right to
>left) as this:
>
>(a = (b = c)) <=== right to left associativity

Yes, that's how it's parsed.
No, that doesn't impose requirements on the order things are actually
done. All that's required is that these happen:
- c is evaluated to get a value
- The value of c, converted appropriately, is stored in b
- The value stored in b, converted appropriately, is stored in a.
Which order they happen in depends only on dependencies between them,
and the store to a only depends on the value stored in b being calculated
(and even there the compiler may be able to determine what it is without
actually calculating it - see my example below), not on it actually
being stored in b.

If they all have the same types, any self-respecting optimizing compiler
will load the value once and store it twice without doing anything else
between the stores. In the simple case it will assign to b first, but
there's no reason why it needs to, and (especially if they're not both
local variables) there might be good reasons not to.

If different types (and, therefore, conversions) are involved, it's even
easier to come up with a perfectly reasonable way for the store to a to
happen first, or for both stores to happen at the same time.
Consider, f'rexample, a word-addressed machine where char * and void *
(as "byte pointers") have a different representation than other pointers.
(Such machines do exist, and as far as I know have C implementations;
Chris Torek likes using one of them as an example.)
If a and c are, say, int * and b is a void *, then the most sensible
way to execute "a=b=c" is:
--------
store r1,a1 ;Store word pointer
shl r1,2 ;Convert word pointer to byte pointer
store r1,a1 ;Store byte pointer
--------
Since the word pointer -> byte pointer -> word pointer conversion ends
up being a no-op, this reordering gives the exact same results as if
the double conversion had been done, and is therefore just as valid.

For the case where they're all the same type, consider

>Consider also (all ints):
>
>a + b + c
>
>the value in a is equal to -b, the value in both b and c is almost
>INT_MAX, so will over flow occur?

If the value of a+b can be added to c without overflowing, the generated
code has to act as if no overflow occurred, since the value being added
to c is the value of a+b.
If the compiler knows that, f'rexample, the machine uses 2s-complement
with silent wraparound on overflow, it's free to generate code that
computes b+c and then adds a to that, since it knows that the result
will be the same whether something overflows or not.

The only requirement is that the correct values get stored in the
correct places before the next sequence point. Operations without
dependencies, or operations that can commute with each other, can be
(and, with optimizing compilers, usually are) done in any order the
compiler likes, no matter what the code says.

dave

--
Dave Vandervies
I can't pick up the phone and ask for "Farsley double one double three"
whenever I fancy a pizza. Well, I could, but I'd stay hungry.
--Peter Corlett in the scary devil monastery

Dave Vandervies, Feb 11, 2005
19. ### Luke WuGuest

Dave Vandervies wrote:
> In article <>,
> Luke Wu <> wrote:
>
> >No, the compiler views it according to the associativity rules(right

to
> >left) as this:
> >
> >(a = (b = c)) <=== right to left associativity

>
> Yes, that's how it's parsed.
> No, that doesn't impose requirements on the order things are actually
> done. All that's required is that these happen:
> - c is evaluated to get a value
> - The value of c, converted appropriately, is stored in b
> - The value stored in b, converted appropriately, is stored in a.
> Which order they happen in depends only on dependencies between them,
> and the store to a only depends on the value stored in b being

calculated
> (and even there the compiler may be able to determine what it is

without
> actually calculating it - see my example below), not on it actually
> being stored in b.
>

The compiler can do anything it wants at the machine level, but the
result must not differ from what we would get if we did b=c , a=b at
the abstract machine level

if in (a = (b = c)) , the order really does matter (if a, b, c are sub
expressions), then the order implied by the brackets must be taken, if
order doesn't matter, the compiler can do anything

the result of anything the compiler does, must equal the result of:
b=c,a=b

I am absolutely certain of this.

Luke Wu, Feb 12, 2005
20. ### Jack KleinGuest

On 11 Feb 2005 16:12:57 -0800, "Luke Wu" <>
wrote in comp.lang.c:

>
> Dave Vandervies wrote:
> > In article <>,
> > Luke Wu <> wrote:
> >
> > >No, the compiler views it according to the associativity rules(right

> to
> > >left) as this:
> > >
> > >(a = (b = c)) <=== right to left associativity

> >
> > Yes, that's how it's parsed.
> > No, that doesn't impose requirements on the order things are actually
> > done. All that's required is that these happen:
> > - c is evaluated to get a value
> > - The value of c, converted appropriately, is stored in b
> > - The value stored in b, converted appropriately, is stored in a.
> > Which order they happen in depends only on dependencies between them,
> > and the store to a only depends on the value stored in b being

> calculated
> > (and even there the compiler may be able to determine what it is

> without
> > actually calculating it - see my example below), not on it actually
> > being stored in b.
> >

>
> The compiler can do anything it wants at the machine level, but the
> result must not differ from what we would get if we did b=c , a=b at
> the abstract machine level
>
> if in (a = (b = c)) , the order really does matter (if a, b, c are sub
> expressions), then the order implied by the brackets must be taken, if
> order doesn't matter, the compiler can do anything
>
> the result of anything the compiler does, must equal the result of:
> b=c,a=b
>
> I am absolutely certain of this.

And I am absolutely certain that you are wrong. The difference is
that I can cite the reference to the C language standard to back up my
certainty, and you cannot.

The C standard specifically states, in paragraph 2 of section 6.5:

========
Between the previous and next sequence point an object shall have its
stored value modified at most once by the evaluation of an expression.
Furthermore, the prior value shall be read only to determine the value
to be stored.70)
========

That "70" at the end is a reference to a footnote, subscripts don't
look special in plain text. But here is the context of footnote 70:

========
70) This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a = i;
========

So you may be certain, but you are certainly wrong.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html

Jack Klein, Feb 12, 2005