difference between pointers

V

Varun Tewari

hello all,

I get this doubt about this behavior of C.

consider the following code.

int a,b,d1,d2,diff;

d1= &a;
d2 = &b;
diff = &a-&b;
printf("\nDifference between address: %d", diff);
diff = d1-d2;
printf("\nDifference between address(stored in integers): %d", diff);

ideally, both printf should result same output.
but as expected diff = d1-d2 gives 4.
but diff = &a-&b gives 1.

Why so when C doesn't really support operator overloading.
 
E

Eric Sosman

hello all,

I get this doubt about this behavior of C.

consider the following code.

int a,b,d1,d2,diff;

d1= &a;
d2 = &b;
diff = &a-&b;
printf("\nDifference between address: %d", diff);
diff = d1-d2;
printf("\nDifference between address(stored in integers): %d", diff);

ideally, both printf should result same output.
but as expected diff = d1-d2 gives 4.
but diff = &a-&b gives 1.

Why so when C doesn't really support operator overloading.

The short (and technical, and not very helpful) answer is
that the code's behavior is undefined: The C language doesn't
specify what should happen, so *anything* might happen.

A longer answer ...

First, pointer arithmetic always operates in units of the
pointed-at type. Adding 1 to an `int*' advances the pointer
to the next `int', adding 1 to a `double*' advances to the next
`double', and so on. Even if an `int' occupies four bytes and
a `double' occupies eight, adding 1 advances the pointer by the
proper distance for its type.

... so subtraction works the same way: If you start with an
`int*', add 1 to produce another pointer to the next `int', and
then subtract the two values, what do you get? You get 1: the
distance between the two objects is expressed in multiples of
the object size. If you start with a pointer `p' and derive a
new pointer `q' by computing `q = p + 3', it should come as no
surprise that `q - p' yields 3.

However, this adding and subtracting only works when you're
navigating within in an array that contains the pointed-at objects.
That's the only way to be sure of the right adjacency and spacing
that allows pointer arithmetic to be defined. Consider: If you
have two objects that are six bytes long, and if they exist at
addresses eight bytes apart, the distance between them is not a
multiple of the size and pointer arithmetic falls down: You can't
add 1 to a pointer and have it advance by one-and-a-third objects!

... and that's where the undefined behavior enters your code.
Since `a' and `b' are free-standing objects, unrelated to each
other and not part of the same array, subtracting pointers to them
cannot be guaranteed to produce a sensible answer. So C does not
promise that anything sensible will happen; C says "the behavior
is undefined" and just leaves it at that. In your case it seems
that `a' and `b' did in fact wind up in adjacent memory regions,
but that's a coincidence, not something C promises nor that you
can rely on.

Next topic: Why 1 vs. 4?

C promises that a pointer can be converted to some kind of
integer, but says very little about how wide an integer is needed
and says nothing at all about the nature of the conversion. You
take a pointer, convert it to an `int', and you get some kind of
value. (It is not even guaranteed that you'll get the same value
every time!) In your case, it seems that the address part of your
pointer (or part of it) simply got transliterated into a bag of
bits that were then interpreted as an `int' value -- that's a very
common scheme, but not the only one.

But notice what's left behind: The pointer "knew" what kind
of object it pointed to, and hence the size of that object, and
thus knew how to compensate for that size when doing arithmetic.
The `int' resulting from conversion, though, has no information
about the type of object the pointer aimed at, and cannot make
adjustments for object size. So when you subtract the integers
there's no adjustment: You get the distance between the objects
expressed not in object-units, but in bytes (again, this is a
common outcome but not the only possibility).

Pointers are not "just addresses," but "addresses with type."
 
T

Tim Rentsch

Varun Tewari said:
hello all,

I get this doubt about this behavior of C.

consider the following code.

int a,b,d1,d2,diff;

d1= &a;
d2 = &b;
diff = &a-&b;
printf("\nDifference between address: %d", diff);
diff = d1-d2;
printf("\nDifference between address(stored in integers): %d", diff);

ideally, both printf should result same output.
but as expected diff = d1-d2 gives 4.
but diff = &a-&b gives 1.

Why so when C doesn't really support operator overloading.

Compiling this code should have produced at least one warning or
error message. If it did not, you are very likely operating the
compiler in a non-conforming mode; in other words, the language
accepted may look a lot like C, but it isn't C.

If the compiler you are using is gcc, try these options:

gcc -ansi -pedantic-errors

which directs gcc to operate according to how standard C is
defined, rather than the "C-like but not C" language that
gcc accepts by default.
 
T

Tim Rentsch

Eric Sosman said:
The short (and technical, and not very helpful) answer is
that the code's behavior is undefined: The C language doesn't
specify what should happen, so *anything* might happen.

Except that, before getting to that point, a diagnostic is
required -- assigning an integer to a pointer is a constraint
violation.
[snip]

C promises that a pointer can be converted to some kind of
integer, but says very little about how wide an integer is needed
and says nothing at all about the nature of the conversion. You
take a pointer, convert it to an `int', and you get some kind of
value. (It is not even guaranteed that you'll get the same value
every time!) In your case, it seems that the address part of your
pointer (or part of it) simply got transliterated into a bag of
bits that were then interpreted as an `int' value -- that's a very
common scheme, but not the only one.

This is right in spirit but a lot of the details are wrong.

C does promise that a pointer can be converted to one particular
integer type; however, the conversion is completely specified,
as is the width of the integer, because the type in question is
the "boolean" type _Bool. The Standard does not guarantee that
a pointer can be converted to any other integer type.

If the header file <stdint.h> defines the types intptr_t,
then these types are guaranteed to work for converting any valid
pointer to void (ie, any valid pointer value of type 'void *');
moreover, converting back the other direction is guaranteed to
compare equal to the original pointer value.

There is no guarantee that a pointer to any type other than
void can be converted to any integer type other than _Bool. A
pointer to void can be converted to the types intptr_t, but
only if the implementation defines them, which the Standard
does not require.

On the flip side, the result of converting a pointer to an
integer type is implementation-defined, which means each
implementation has to document what it does. So, for any
specific implementation, you can find out which integer types
may be used to convert different kinds of pointer values, and
what the result of those conversions will be.
 
K

Keith Thompson

Eric Sosman said:
I get this doubt about this behavior of C.

consider the following code.

int a,b,d1,d2,diff;

d1= &a;
d2 = &b;
diff = &a-&b;
printf("\nDifference between address: %d", diff);
diff = d1-d2;
printf("\nDifference between address(stored in integers): %d", diff);
[SNIP]
Next topic: Why 1 vs. 4?

C promises that a pointer can be converted to some kind of
integer, but says very little about how wide an integer is needed
and says nothing at all about the nature of the conversion. You
take a pointer, convert it to an `int', and you get some kind of
value. (It is not even guaranteed that you'll get the same value
every time!) In your case, it seems that the address part of your
pointer (or part of it) simply got transliterated into a bag of
bits that were then interpreted as an `int' value -- that's a very
common scheme, but not the only one.

You're assuming that this:

d1 = &a; /* where d1 and a are both of type int */

specifies a conversion. Nothing in the C standard says or implies
that. The types int and int* are not assignment-compatible, so
the assignment is a constraint violation, requiring a diagnostic.
*If* the compiler chooses to generate an executable after issuing
the diagnostic, nothing in the C standard says anything about how
it behaves.

It happens that, in most implementations, the behavior is equivalent
to:

d1 = (int)&a;

for historical reasons. But you shouldn't depend on that; a
conforming implementation could do *anything*. Don't waste your
time running the program, just fix the source code.

And in this case, the best fix is almost certainly *not* to add
the cast (adding casts to silence warnings is rarely a good idea),
but to change the declaration of d1.

(I'm leaving aside the fact that the behavior of `&a - &b` is
undefined; others have covered that.)

[...]
 
B

BartC

Varun Tewari said:
hello all,

I get this doubt about this behavior of C.

consider the following code.

int a,b,d1,d2,diff;

d1= &a;
d2 = &b;
diff = &a-&b;
printf("\nDifference between address: %d", diff);
diff = d1-d2;
printf("\nDifference between address(stored in integers): %d", diff);

ideally, both printf should result same output.
but as expected diff = d1-d2 gives 4.
but diff = &a-&b gives 1.

Why so when C doesn't really support operator overloading.

I don't understand what overloading has to do with it.

C likes to do pointer arithmetic in terms of 'objects' rather than bytes.
&a-&b gives the difference in number of objects (and a, b happen to be next
to each in memory, so one object difference).

While d1-d2 subtracts one byte address from another, after each is converted
to a plain int so that it no longer knows what kinds of pointers they were.

It would be a little more interesting if a and b weren't aligned on a 4-byte
boundary, and the byte-difference in their addresses wasn't a multiple of 4.
(For this sort of reason, I'd have preferred pointer arithmetic to work in
bytes, or rather chars, but using objects has its advantages too.)
 
T

Tim Rentsch

Keith Thompson said:
Eric Sosman said:
I get this doubt about this behavior of C.

consider the following code.

int a,b,d1,d2,diff;

d1= &a;
d2 = &b;
diff = &a-&b;
printf("\nDifference between address: %d", diff);
diff = d1-d2;
printf("\nDifference between address(stored in integers): %d", diff);
[SNIP]
Next topic: Why 1 vs. 4?

C promises that a pointer can be converted to some kind of
integer, but says very little about how wide an integer is needed
and says nothing at all about the nature of the conversion. You
take a pointer, convert it to an `int', and you get some kind of
value. (It is not even guaranteed that you'll get the same value
every time!) In your case, it seems that the address part of your
pointer (or part of it) simply got transliterated into a bag of
bits that were then interpreted as an `int' value -- that's a very
common scheme, but not the only one.

You're assuming that this:

d1 = &a; /* where d1 and a are both of type int */

specifies a conversion. Nothing in the C standard says or implies
that. The types int and int* are not assignment-compatible, so
the assignment is a constraint violation, requiring a diagnostic.
*If* the compiler chooses to generate an executable after issuing
the diagnostic, nothing in the C standard says anything about how
it behaves. [...] a conforming implementation could do *anything*.
[snip elaboration]

I'm not sure what your reasoning is to reach this conclusion.
Certainly this assignment has a constraint violation, but you're
saying, in effect, that it has undefined behavior. Presumably
the underlying reasoning is one of two things, namely:

A. There is a constraint violation, and any constraint
violation is necessarily undefined behavior; or

B. The assignment statement is trying to assign a pointer
type to an integer type, and nothing in the Standard
says how to do that, so there is undefined behavior.

IMO point A is incorrect, although I would agree the point
is debatable. Section 4 paragraph 3 says in part:

If a ``shall'' or ``shall not'' requirement that appears
outside of a constraint or runtime-constraint is violated,
the behavior is undefined.

This statement makes it reasonable to infer that a constraint
violation might _not_ result in undefined behavior in some
instances, as otherwise there is no point in excluding it.
("The exception proves the rule in cases not excepted.")

Turning to point B, I think it is clearly just wrong, because
of 6.5.16.1 p 2.

Aside from the constraint violation, I don't see anything that
makes this assignment have undefined behavior. If it is true
that a constraint violation is not /ipso facto/ undefined
behavior, then the behavior of this assignment is well-defined.
A compiler is free to reject it (with the necessary diagnostic)
because of the constraint violation; but if the compiler chooses
to accept it, then the assignment must behave the same way that

d1 = (int) &a;

would.
 
V

Varun Tewari

Yep it did give warning.Thnx for pointing the correct gcc option for correct ansi parsing.
 
K

Keith Thompson

Tim Rentsch said:
You're assuming that this:

d1 = &a; /* where d1 and a are both of type int */

specifies a conversion. Nothing in the C standard says or implies
that. The types int and int* are not assignment-compatible, so
the assignment is a constraint violation, requiring a diagnostic.
*If* the compiler chooses to generate an executable after issuing
the diagnostic, nothing in the C standard says anything about how
it behaves. [...] a conforming implementation could do *anything*.
[snip elaboration]

I'm not sure what your reasoning is to reach this conclusion.
Certainly this assignment has a constraint violation, but you're
saying, in effect, that it has undefined behavior. Presumably
the underlying reasoning is one of two things, namely:

A. There is a constraint violation, and any constraint
violation is necessarily undefined behavior; or

B. The assignment statement is trying to assign a pointer
type to an integer type, and nothing in the Standard
says how to do that, so there is undefined behavior.

IMO point A is incorrect, although I would agree the point
is debatable. Section 4 paragraph 3 says in part:

If a ``shall'' or ``shall not'' requirement that appears
outside of a constraint or runtime-constraint is violated,
the behavior is undefined.

IMHO A is correct (programs with constraint violations have undefined
behavior), though I'm not sure I can prove it.
This statement makes it reasonable to infer that a constraint
violation might _not_ result in undefined behavior in some
instances, as otherwise there is no point in excluding it.
("The exception proves the rule in cases not excepted.")

Perhaps, but only if the behavior is actually defined somewhere.
Turning to point B, I think it is clearly just wrong, because
of 6.5.16.1 p 2.

Which says:

In *simple assignment* (=), the value of the right operand is
converted to the type of the assignment expression and replaces the
value stored in the object designated by the left operand.

That's an interesting point, but consider the definition of "constraint"
in 3.8:

restriction, either syntactic or semantic, by which the exposition
of language elements is to be interpreted

So the statement about the semantics of a simplea ssignment "is to
be interpreted" in the context of the restriction on the operands.
My conclusion from that is that if the constraint is violated,
the statement doesn't apply.

If the constraint is violated, it isn't a simple assignment.
We don't know what it is, but it's not part of a valid C program.

A compiler is free to reject a program containing such an assignment.
If it does so, the conversion described in 6.5.16.1p2 does not
occur -- but that doesn't mean the compiler is non-conforming.

I suppose you could (and apparently do) interpret it to mean that
the conversion occurs *if* the program is not rejected. I find
that interpretation a bit strained.
Aside from the constraint violation, I don't see anything that
makes this assignment have undefined behavior. If it is true
that a constraint violation is not /ipso facto/ undefined
behavior, then the behavior of this assignment is well-defined.
A compiler is free to reject it (with the necessary diagnostic)
because of the constraint violation; but if the compiler chooses
to accept it, then the assignment must behave the same way that

d1 = (int) &a;

would.

I disagree.

Note also that, quoting 4p6:

A conforming implementation may have extensions [...] provided they
do not alter the behavior of any strictly conforming program.

which implies that such an extension *could* alter the behavior of a
program containing such an assignment.

(It could also imply that an extension could alter the behavior
of printf("%d\n", INT_MAX), which I find a bit troubling. I'm not
sure that strict conformance was the best criterion to use there.)
 
J

Joe Pfeiffer

christian.bau said:
You don't have a doubt, you have a question. A "doubt" is a "feeling
of uncertainty or lack of conviction".

There are areas of the world in which "doubt" is used exactly as
Americans and Europeans use "question". This was one of the things I
had to get used to when I started having significant numbers of students
from India.
 
K

Kenny McCormack

There are areas of the world in which "doubt" is used exactly as
Americans and Europeans use "question". This was one of the things I
had to get used to when I started having significant numbers of students
from India.

Which leads inevitably to the ago-old question. Say you find yourself in a
situation where, speaking on the topic of dogs, large numbers of people call
a tail a "leg". Do you accept that as acceptable usage and go along with
the crowd, or do you patiently instruct them, over and over, that a tail is
not a leg?

And note, given that in this newsgroup, people never get tired of bitching
about "void main" or telling people not to cast the return value of malloc,
or about how not #includ'ing stdio.h causes undefined behavior, I don't
think there's much likelihood they'll stop bitching about people misusing
the word "doubt".

people not
 
J

Joe Pfeiffer

Which leads inevitably to the ago-old question. Say you find yourself in a
situation where, speaking on the topic of dogs, large numbers of people call
a tail a "leg". Do you accept that as acceptable usage and go along with
the crowd, or do you patiently instruct them, over and over, that a tail is
not a leg?

And note, given that in this newsgroup, people never get tired of bitching
about "void main" or telling people not to cast the return value of malloc,
or about how not #includ'ing stdio.h causes undefined behavior, I don't
think there's much likelihood they'll stop bitching about people misusing
the word "doubt".

Those are legitimate concerns about C.
 
K

Keith Thompson

BartC said:
I don't understand what overloading has to do with it.

The "-" operator actually is overloaded: it can be applied to
integers, floating-point values, or pointers. What C doesn't
support is *user-defined* operator overloading.
C likes to do pointer arithmetic in terms of 'objects' rather than bytes.
&a-&b gives the difference in number of objects (and a, b happen to be next
to each in memory, so one object difference).

While d1-d2 subtracts one byte address from another, after each is converted
to a plain int so that it no longer knows what kinds of pointers they were.

It would be a little more interesting if a and b weren't aligned on a 4-byte
boundary, and the byte-difference in their addresses wasn't a multiple of 4.
(For this sort of reason, I'd have preferred pointer arithmetic to work in
bytes, or rather chars, but using objects has its advantages too.)

The main purpose of pointer arithmetic is to access elements within
arrays. For example, the indexing operator [] is defined in terms
of pointer arithmetic. The distance between elements of an array
is always a whole multiple of the size of each element.

If you want the difference *in bytes* between two pointer values,
you can just convert both pointers to char*.

Yes, pointer arithmetic could have been defined in terms of bytes, but
it's more convenient the way it is.
 
Ø

Øyvind Røtvold

(e-mail address removed) (Kenny McCormack) writes:

[ ... ]
Which leads inevitably to the ago-old question. Say you find yourself in a
situation where, speaking on the topic of dogs, large numbers of people call
a tail a "leg". Do you accept that as acceptable usage and go along with
the crowd, or do you patiently instruct them, over and over, that a tail is
not a leg?

Or perhaps: Say you find yourself in a situation where, speaking on
the topic of "hunds", large numbers of people call a "shank" a "leg".
Do you accept that as acceptable usage and go along with the crowd, or
do you patiently instruct them, over and over, that a leg is not a
shank? And when you've given up on that someone starts to call a
"hund" a "dog", and here we go again.
 
K

Kenny McCormack

(e-mail address removed) (Kenny McCormack) writes:

[ ... ]
Which leads inevitably to the ago-old question. Say you find yourself in a
situation where, speaking on the topic of dogs, large numbers of people call
a tail a "leg". Do you accept that as acceptable usage and go along with
the crowd, or do you patiently instruct them, over and over, that a tail is
not a leg?

Or perhaps: Say you find yourself in a situation where, speaking on
the topic of "hunds", large numbers of people call a "shank" a "leg".
Do you accept that as acceptable usage and go along with the crowd, or
do you patiently instruct them, over and over, that a leg is not a
shank? And when you've given up on that someone starts to call a
"hund" a "dog", and here we go again.

Or you could just say "To heck with it all" and go back to bitching about
void main() and casting the return value of malloc().

--
Modern Christian: Someone who can take time out from
complaining about "welfare mothers popping out babies we
have to feed" to complain about welfare mothers getting
abortions that PREVENT more babies to be raised at public
expense.
 
V

Varun Tewari

Thnx Everyone.

For me my doubts are cleared, and for those who think it wasn't a doubt but a question, yes my questions are well answered.

:)
 
T

Tim Rentsch

Varun Tewari said:
Yep it did give warning. Thnx for pointing the correct gcc option for
correct ansi parsing.

You may also want to try

gcc -std=c99 -pedantic-errors

or (if you have a newer version of gcc)

gcc -std=c11 -pedantic-errors

instead of using -ansi, which specifies the 1990 version of ISO C.
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
You're assuming that this:

d1 = &a; /* where d1 and a are both of type int */

specifies a conversion. Nothing in the C standard says or implies
that. The types int and int* are not assignment-compatible, so
the assignment is a constraint violation, requiring a diagnostic.
*If* the compiler chooses to generate an executable after issuing
the diagnostic, nothing in the C standard says anything about how
it behaves. [...] a conforming implementation could do *anything*.
[snip elaboration]

I'm not sure what your reasoning is to reach this conclusion.
Certainly this assignment has a constraint violation, but you're
saying, in effect, that it has undefined behavior. Presumably
the underlying reasoning is one of two things, namely:

A. There is a constraint violation, and any constraint
violation is necessarily undefined behavior; or

B. The assignment statement is trying to assign a pointer
type to an integer type, and nothing in the Standard
says how to do that, so there is undefined behavior.

IMO point A is incorrect, although I would agree the point
is debatable. Section 4 paragraph 3 says in part:

If a ``shall'' or ``shall not'' requirement that appears
outside of a constraint or runtime-constraint is violated,
the behavior is undefined.

IMHO A is correct (programs with constraint violations have
undefined behavior), though I'm not sure I can prove it.
This statement makes it reasonable to infer that a constraint
violation might _not_ result in undefined behavior in some
instances, as otherwise there is no point in excluding it.
("The exception proves the rule in cases not excepted.")

Perhaps, but only if the behavior is actually defined somewhere.

The behavior is defined by the semantics paragraphs of "Simple
assignment", which the expression in question must have been
identified as being. (This point expanded on below.)
Which says:

In *simple assignment* (=), the value of the right operand is
converted to the type of the assignment expression and
replaces the value stored in the object designated by the left
operand.

That's an interesting point, but consider the definition of
"constraint" in 3.8:

restriction, either syntactic or semantic, by which the exposition
of language elements is to be interpreted

So the statement about the semantics of a simplea ssignment "is to
be interpreted" in the context of the restriction on the operands.
My conclusion from that is that if the constraint is violated,
the statement doesn't apply.

If the constraint is violated, it isn't a simple assignment.
We don't know what it is, but it's not part of a valid C program.

The problem with this reasoning is that the compiler must have
identified the expression as a simple assignment, because the
constraint only applies to simple assignments, and violating a
constraint requires a diagnostic. If we don't know that the
expression is a simple assignment, then there is no constraint
violation, and the compiler would be free to treat the program as
having undefined behavior, without issuing a diagnostic. This is
a classic "you can't have it both ways" kind of situation. The
only reasonable way out is to say the compiler must identify the
expression in question as a simple assignment, and proceed
accordingly.
A compiler is free to reject a program containing such an assignment.
If it does so, the conversion described in 6.5.16.1p2 does not
occur -- but that doesn't mean the compiler is non-conforming.

I don't see what this has to do with anything. Obviouly a
program that did not successfully compile (ie, was rejected)
won't have any of its semantic actions carried out. There are a
variety of reasons why a compiler might reject a program;
rejecting it because it has a constraint violation isn't any
different in this regard.
I suppose you could (and apparently do) interpret it to mean that
the conversion occurs *if* the program is not rejected. I find
that interpretation a bit strained.

I don't see why. It seems reasonable that the semantics described
under "Simple assignment" would apply; detabable maybe, but not
unreasonable, certainly not a big stretch. And those semantics
clearly spell out a particular well-defined behavior (and which
includes the conversion).
I disagree.

Let me point out that the final sentence is predicated on the 'If
it is true that ...' condition given earlier in the paragraph.
In this paragraph it is not my intention to make an absolute
statement, only a relative one.

To try to bring the conversation up a level: the essential point I
was trying to make is that the question is not black and white.
Reasonable people can disagree here. In the interest of giving a
fair presentation under such circumstances, I think it's better to
give a qualified statement rather than treating the matter as
completely settled.
Note also that, quoting 4p6:

A conforming implementation may have extensions [...] provided they
do not alter the behavior of any strictly conforming program.

which implies that such an extension *could* alter the behavior of a
program containing such an assignment.

(It could also imply that an extension could alter the behavior
of printf("%d\n", INT_MAX), which I find a bit troubling. I'm not
sure that strict conformance was the best criterion to use there.)

The area of "extensions" is a little murky. Looking through the
section on common extensions, it isn't clear just how much is
allowed (at least one example seems to imply that an extension
could change the meaning of a strictly conforming program).
Certainly extensions have great latitude to re-define behavior,
as your example illustrates, even if it isn't clear just how
great that latitude is.

However, regarding what is required for this kind of assignment
expression, the matter of extensions can easily be rendered moot,
because extensions are reguired to be documented. We can simply
ask the question of what behavior is required for implementations
that do not document any extensions in such cases.
 
A

army1987

There is no guarantee that a pointer to any type other than void can be
converted to any integer type other than _Bool. A pointer to void can
be converted to the types intptr_t, but only if the implementation
defines them, which the Standard does not require.


Is there any good reason why (intptr_t)&i isn't required to be the same
as (intptr_t)(void *)&i? (Crossposted to comp.std.c.)
 
A

army1987

Which leads inevitably to the ago-old question. Say you find yourself
in a situation where, speaking on the topic of dogs, large numbers of
people call a tail a "leg". Do you accept that as acceptable usage and
go along with the crowd, or do you patiently instruct them, over and
over, that a tail is not a leg?

And note, given that in this newsgroup, people never get tired of
bitching about "void main" or telling people not to cast the return
value of malloc, or about how not #includ'ing stdio.h causes undefined
behavior, I don't think there's much likelihood they'll stop bitching
about people misusing the word "doubt".

The difference being that there's an ISO standard defining what "void main
()" means or doesn't mean, but there's no official standard defining what
"doubt" means or doesn't mean; there are _de facto_ standards for that
but they don't happen to agree with each other. (I think it's most
useful to stick to one of the _de facto_ standards that are followed by a
sizeable number of native English speakers and don't confuse people
following different _de facto_ standards too much, and the particular _de
facto_ standard according to which "doubt" can mean 'question' doesn't
fulfil these criteria; but still.)
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top