Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #73851 > unrolled thread
| Started by | fl <rxjwg98@gmail.com> |
|---|---|
| First post | 2015-10-26 06:21 -0700 |
| Last post | 2015-10-26 09:50 -0700 |
| Articles | 17 — 9 participants |
Back to article view | Back to comp.lang.c
What is the value after operator '!'? fl <rxjwg98@gmail.com> - 2015-10-26 06:21 -0700
Re: What is the value after operator '!'? Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-10-26 09:29 -0400
Re: What is the value after operator '!'? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-26 13:42 +0000
Re: What is the value after operator '!'? supercat@casperkitty.com - 2015-10-26 07:53 -0700
Re: What is the value after operator '!'? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-26 17:37 +0000
Re: What is the value after operator '!'? Keith Thompson <kst-u@mib.org> - 2015-10-26 11:05 -0700
Re: What is the value after operator '!'? supercat@casperkitty.com - 2015-10-26 11:38 -0700
Re: What is the value after operator '!'? glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-10-26 20:27 +0000
Re: What is the value after operator '!'? supercat@casperkitty.com - 2015-10-26 14:16 -0700
Re: What is the value after operator '!'? Keith Thompson <kst-u@mib.org> - 2015-10-26 17:15 -0700
Re: What is the value after operator '!'? Keith Thompson <kst-u@mib.org> - 2015-10-26 17:12 -0700
Re: What is the value after operator '!'? Ian Collins <ian-news@hotmail.com> - 2015-10-27 10:27 +1300
Re: What is the value after operator '!'? Keith Thompson <kst-u@mib.org> - 2015-10-26 15:15 -0700
Re: What is the value after operator '!'? supercat@casperkitty.com - 2015-10-26 16:16 -0700
Re: What is the value after operator '!'? Keith Thompson <kst-u@mib.org> - 2015-10-27 08:39 -0700
Re: What is the value after operator '!'? Richard Heathfield <rjh@cpax.org.uk> - 2015-10-26 14:04 +0000
Re: What is the value after operator '!'? Geoff <geoff@invalid.invalid> - 2015-10-26 09:50 -0700
| From | fl <rxjwg98@gmail.com> |
|---|---|
| Date | 2015-10-26 06:21 -0700 |
| Subject | What is the value after operator '!'? |
| Message-ID | <7229ebda-7352-441e-9946-ccee1ce81b03@googlegroups.com> |
Hi,
I saw coding such as: a=!a before. Today, when I write my code below, I find
if on_off_flag==0, on_off_flag will be '1' after
on_off_flag = !on_off_flag;
It is a surprise to me. I supposed it will be 0xFFFF,FFFF for integer
on_off_flag
'!' is an inverse operator or not?
Thanks,
static int on_off_flag = 0;
static int on_off_counter = 0;
on_off_counter++;
if (on_off_counter == 1000){
on_off_counter = 0;
on_off_flag = !on_off_flag;
[toc] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2015-10-26 09:29 -0400 |
| Message-ID | <n0l9og$hbl$1@dont-email.me> |
| In reply to | #73851 |
On 10/26/2015 9:21 AM, fl wrote:
> Hi,
>
> I saw coding such as: a=!a before. Today, when I write my code below, I find
> if on_off_flag==0, on_off_flag will be '1' after
>
> on_off_flag = !on_off_flag;
>
> It is a surprise to me. I supposed it will be 0xFFFF,FFFF for integer
> on_off_flag
>
> '!' is an inverse operator or not?
It inverts a logical value: true (anything non-zero) becomes
false (zero), false (zero) becomes true (one).
(It is also part of the != operator, not a "combination" or
"compound" but an operator in its own right. Just as == is not
the combination of = and =, != is not the combination of ! and =.)
Perhaps you are thinking of the ~ operator, which inverts the
bits of its operand. This operator works only on the various kinds
of integers, and should probably only be applied to unsigned types
because flipping a sign bit runs into possible portability problems.
--
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-10-26 13:42 +0000 |
| Message-ID | <87k2q9lp98.fsf@bsb.me.uk> |
| In reply to | #73851 |
fl <rxjwg98@gmail.com> writes: > Hi, > > I saw coding such as: a=!a before. Today, when I write my code below, I find > if on_off_flag==0, on_off_flag will be '1' after > > on_off_flag = !on_off_flag; > > It is a surprise to me. I supposed it will be 0xFFFF,FFFF for integer > on_off_flag You want ~ for that though, technically, the result is not 0xFFFFFFFF. That's a very large positive number and the result of ~0 is (on most systems) -1. > '!' is an inverse operator or not? From the C standard: "The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0." <snip> -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2015-10-26 07:53 -0700 |
| Message-ID | <090eee37-7aeb-47e7-b195-ce3900b30fff@googlegroups.com> |
| In reply to | #73853 |
On Monday, October 26, 2015 at 8:43:14 AM UTC-5, Ben Bacarisse wrote:
> From the C standard:
>
> "The result of the logical negation operator ! is 0 if the value of
> its operand compares unequal to 0, 1 if the value of its operand
> compares equal to 0."
It may be worth noting that 0 doesn't always mean "zero". If p is a pointer,
then "p==0" will coerce the *literal* zero to a null pointer; likewise !p
will compare p against a null pointer. It would be perfectly legitimate for
a system to define a mapping between integers and pointers such that:
unsigned char *p = 0; // A literal zero -- a null pointer
unsigned char *q = (unsigned char*)(intptr_t)(1-1); // A zero value
// The following two expressions both return 1
int resp1 = !p; // Since p is null)
int resq1 = !(intptr_t)q; // Since (intptr_t)q is zero
// The following expressions could return 0 if a system uses a bit
// pattern for null which, when cast to intptr_t does not yield zero.
int resp2 = !(intptr_t)p; // Comparing possibly-non-zero number vs zero
int resq2 = !q; // Compare possibly non-null pointer against null
On most C implementations the distinction doesn't matter, but if one wants
to write strictly-conforming code it does.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-10-26 17:37 +0000 |
| Message-ID | <87si4xjzui.fsf@bsb.me.uk> |
| In reply to | #73859 |
supercat@casperkitty.com writes: > On Monday, October 26, 2015 at 8:43:14 AM UTC-5, Ben Bacarisse wrote: >> From the C standard: >> >> "The result of the logical negation operator ! is 0 if the value of >> its operand compares unequal to 0, 1 if the value of its operand >> compares equal to 0." > > It may be worth noting that 0 doesn't always mean "zero". If p is a pointer, > then "p==0" will coerce the *literal* zero to a null pointer; I would not put it quite like that. 0 always means zero, it's just that an integer constant expression with the value 0 is a null pointer constant as well as being an integer zero. The 0 is not coerced to being a null pointer, it always is one. There *is* a conversion implicit in writing p==0, but it's the conversion of the null pointer constant to a null pointer of the same type as p. Your wording might be taken to suggest that there is some arithmetic type to pointer type conversion going on. > likewise !p > will compare p against a null pointer. It would be perfectly legitimate for > a system to define a mapping between integers and pointers such that: > > unsigned char *p = 0; // A literal zero -- a null pointer > unsigned char *q = (unsigned char*)(intptr_t)(1-1); // A zero value > > // The following two expressions both return 1 > > int resp1 = !p; // Since p is null) > int resq1 = !(intptr_t)q; // Since (intptr_t)q is zero > > // The following expressions could return 0 if a system uses a bit > // pattern for null which, when cast to intptr_t does not yield zero. > > int resp2 = !(intptr_t)p; // Comparing possibly-non-zero number vs zero > int resq2 = !q; // Compare possibly non-null pointer against null As for the very last part, I don't think so. Both p and q are null pointers of the same type. Whilst I agree that !(intptr_t)p might be 0, I can't see how can !q be anything other than 1. <snip> -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-10-26 11:05 -0700 |
| Message-ID | <ln8u6pfqup.fsf@kst-u.example.com> |
| In reply to | #73885 |
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> supercat@casperkitty.com writes:
>> On Monday, October 26, 2015 at 8:43:14 AM UTC-5, Ben Bacarisse wrote:
>>> From the C standard:
>>>
>>> "The result of the logical negation operator ! is 0 if the value of
>>> its operand compares unequal to 0, 1 if the value of its operand
>>> compares equal to 0."
>>
>> It may be worth noting that 0 doesn't always mean "zero". If p is a
>> pointer, then "p==0" will coerce the *literal* zero to a null
>> pointer;
>
> I would not put it quite like that. 0 always means zero, it's just that
> an integer constant expression with the value 0 is a null pointer
> constant as well as being an integer zero. The 0 is not coerced to
> being a null pointer, it always is one.
A metaquibble: 0 is not a *null pointer*, it's a *null pointer
constant*.
A *null pointer* is a value of pointer type that can exist during
program execution. A *null pointer constant* is a construct that can
appear in a C source file. Evaluating a null pointer constant may or
may not yield a runtime null pointer value, depending on the context in
which it appears.
The expression 0 is simultaneously several things: an expression of type
int, an integer constant expression, an octal constant, a null pointer
constant.
> There *is* a conversion
> implicit in writing p==0, but it's the conversion of the null pointer
> constant to a null pointer of the same type as p. Your wording might be
> taken to suggest that there is some arithmetic type to pointer type
> conversion going on.
There is. The expression 0 is of type int. In p==0, if p is of pointer
type, the expression 0 is converted, via the special-case rule in N1570
6.3.2.3p3, from int to the type of p. (This conversion is almost
certainly done at compile time, though the standard doesn't say so.)
[...]
>> unsigned char *p = 0; // A literal zero -- a null pointer
>> unsigned char *q = (unsigned char*)(intptr_t)(1-1); // A zero value
>>
>> // The following two expressions both return 1
>>
>> int resp1 = !p; // Since p is null)
>> int resq1 = !(intptr_t)q; // Since (intptr_t)q is zero
>>
>> // The following expressions could return 0 if a system uses a bit
>> // pattern for null which, when cast to intptr_t does not yield zero.
>>
>> int resp2 = !(intptr_t)p; // Comparing possibly-non-zero number vs zero
>> int resq2 = !q; // Compare possibly non-null pointer against null
>
> As for the very last part, I don't think so. Both p and q are null
> pointers of the same type. Whilst I agree that !(intptr_t)p might be
> 0, I can't see how can !q be anything other than 1.
Agreed. (1-1) is a null pointer constant, and so is (intprt_t)(1-1)
(since casts are permitted in integer constant expressions). An integer
constant expression with the value 0 cast to any pointer type is a null
pointer constant, so (unsigned char*)(intptr_t)(1-1) is a null pointer
constant.
A better example would be:
unsigned char *p = 0;
const int not_a_constant zero = 0;
unsigned char *q = (unsigned char*)zero;
The value of p is a null pointer. The value of q may or may not be.
And converting a null pointer value to intptr_t may or may not yield 0.
> <snip>
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2015-10-26 11:38 -0700 |
| Message-ID | <d0132578-984d-47b0-995e-a3d2aebeeaaf@googlegroups.com> |
| In reply to | #73893 |
On Monday, October 26, 2015 at 1:05:12 PM UTC-5, Keith Thompson wrote: > There is. The expression 0 is of type int. In p==0, if p is of pointer > type, the expression 0 is converted, via the special-case rule in N1570 > 6.3.2.3p3, from int to the type of p. (This conversion is almost > certainly done at compile time, though the standard doesn't say so.) In a system where (char*)x would yield a pointer to physical address x, and where physical address zero was valid, but where (char*)0 [i.e. NULL] was represented by a pointer with some physical address other than zero, would there be any way of writing a pointer constant equal to physical address zero? > > As for the very last part, I don't think so. Both p and q are null > > pointers of the same type. Whilst I agree that !(intptr_t)p might be > > 0, I can't see how can !q be anything other than 1. > > Agreed. (1-1) is a null pointer constant, and so is (intprt_t)(1-1) > (since casts are permitted in integer constant expressions). An integer > constant expression with the value 0 cast to any pointer type is a null > pointer constant, so (unsigned char*)(intptr_t)(1-1) is a null pointer > constant. I guess "1-1" wasn't sufficiently subtle for a compiler to miss that it was really a constant; C# distinguishes between literal zeroes and integer constants whose value happens to equal zero, but I guess C doesn't? Would the value of (int)0.3 be considered an integer constant? What about (int)(1.0E+17+1.0-1.0E+17), whose value would depend upon how floating-point precision was handled? I sometimes wish the C Standard would define an intrinsic which would take a possibly-constant argument and yield a value equal to the argument but behave as though the value wasn't known until run-time since, especially in the embedded-systems world, it may be necessary to have various things take the same amount of time regardless of whether a particular argument is or is not a constant. > A better example would be: > > unsigned char *p = 0; > const int not_a_constant zero = 0; > unsigned char *q = (unsigned char*)zero; > > The value of p is a null pointer. The value of q may or may not be. > > And converting a null pointer value to intptr_t may or may not yield 0. Are there any other cases in C where an expression which the compiler can recognize as being equal to zero, and an expression always happens to yield zero but isn't recognized as such, would both be valid but semantically different? I wonder how much code would break if the Standard were to require that the argument to the cast must have one of a small number of literal forms (e.g. 0, 0L, etc.) rather than merely being any constant expression whose value happens to be zero?
[toc] | [prev] | [next] | [standalone]
| From | glen herrmannsfeldt <gah@ugcs.caltech.edu> |
|---|---|
| Date | 2015-10-26 20:27 +0000 |
| Message-ID | <n0m2bp$r67$1@speranza.aioe.org> |
| In reply to | #73898 |
supercat@casperkitty.com wrote: > On Monday, October 26, 2015 at 1:05:12 PM UTC-5, Keith Thompson wrote: >> There is. The expression 0 is of type int. In p==0, if p is of pointer >> type, the expression 0 is converted, via the special-case rule in N1570 >> 6.3.2.3p3, from int to the type of p. (This conversion is almost >> certainly done at compile time, though the standard doesn't say so.) > In a system where (char*)x would yield a pointer to physical address x, > and where physical address zero was valid, but where (char*)0 [i.e. NULL] > was represented by a pointer with some physical address other than zero, > would there be any way of writing a pointer constant equal to physical > address zero? You only ever need to do that in very specific, system dependent cases. In those cases, you usually know how to do it. You could memcpy() zero bits into a pointer. You could assign (void*)(intptr_t)0 to a pointer. As far as I know, those aren't guaranteed, but then again a system isn't required to have a physical address zero. And even if it does, you might not be allowed to have pointers to it. There have been systems that did no memory protection at the hardware level. All the protection was supplied by the compiler not allowing one to do things like modify the OS. The ones that I know about ran Algol, which doesn't let you do as many things as C does. -- glen
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2015-10-26 14:16 -0700 |
| Message-ID | <109a24dd-df07-42bb-989d-a92425eb0164@googlegroups.com> |
| In reply to | #73908 |
On Monday, October 26, 2015 at 3:27:52 PM UTC-5, glen herrmannsfeldt wrote:
> supercat wrote:
> > In a system where (char*)x would yield a pointer to physical address x,
> > and where physical address zero was valid, but where (char*)0 [i.e. NULL]
> > was represented by a pointer with some physical address other than zero,
> > would there be any way of writing a pointer constant equal to physical
> > address zero?
>
> You only ever need to do that in very specific, system dependent cases.
On the vast majority of systems NULL is represented by all-bits-zero, and
pointers have the same representation as their corresponding intptr_t
values, making the issue largely moot.
On the other hand, it's not terribly uncommon for systems to have something
useful at address zero which code needs to access. If one needs to fetch
something from address zero and not have the compiler decide it should
eliminate the code since it's dereferencing a null pointer, what would be
the most reliable way to do that?
> As far as I know, those aren't guaranteed, but then again a system
> isn't required to have a physical address zero. And even if it does,
> you might not be allowed to have pointers to it.
The situation of interest would be that the hardware has something which is
at address zero which one needs to access, and the only question is whether
the compiler will generate the code for the access rather than deciding that
it doesn't need to.
> There have been systems that did no memory protection at the
> hardware level. All the protection was supplied by the compiler
> not allowing one to do things like modify the OS. The ones that
> I know about ran Algol, which doesn't let you do as many things
> as C does.
In order for a standard-compliant C compiler to be able to do that usefully,
some of the rules about integer types and padding would need to change since
if e.g. sizeof (void*) is 4 and there exists a pointer somewhere in the
universe whose decomposition into "char" values is {1,2,3,4}, then a compiler
must allow code to take the values {1,2,3,4} and produce a copy of that
pointer, regardless of where those numbers came from. I think it would be
useful for the Standard to allow for the possibility of a system where
a "char" variable can hold either a number or an opaque pointer, and other
integer types likewise (so that values of type "char" can round-trip to
other integer types regardless of what they hold), since that would allow
compiler-based sandboxing (and also, btw, enable tracing garbage collection)
but with the Standard as it is neither is really possible.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-10-26 17:15 -0700 |
| Message-ID | <lnegghdv56.fsf@kst-u.example.com> |
| In reply to | #73912 |
supercat@casperkitty.com writes:
> On Monday, October 26, 2015 at 3:27:52 PM UTC-5, glen herrmannsfeldt wrote:
>> supercat wrote:
>> > In a system where (char*)x would yield a pointer to physical address x,
>> > and where physical address zero was valid, but where (char*)0 [i.e. NULL]
>> > was represented by a pointer with some physical address other than zero,
>> > would there be any way of writing a pointer constant equal to physical
>> > address zero?
>>
>> You only ever need to do that in very specific, system dependent cases.
>
> On the vast majority of systems NULL is represented by all-bits-zero, and
> pointers have the same representation as their corresponding intptr_t
> values, making the issue largely moot.
>
> On the other hand, it's not terribly uncommon for systems to have something
> useful at address zero which code needs to access. If one needs to fetch
> something from address zero and not have the compiler decide it should
> eliminate the code since it's dereferencing a null pointer, what would be
> the most reliable way to do that?
Either do it in some compiler-specific way, or convert a non-constant
integer with the value 0 to a pointer type. The latter isn't guaranteed
to work, but "The mapping functions for converting a pointer to an
integer or an integer to a pointer are intended to be consistent with
the addressing structure of the execution environment." (N1570 6.3.2.3,
footnote).
[...]
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-10-26 17:12 -0700 |
| Message-ID | <lnio5tdv9z.fsf@kst-u.example.com> |
| In reply to | #73908 |
glen herrmannsfeldt <gah@ugcs.caltech.edu> writes:
[...]
> You only ever need to do that in very specific, system dependent cases.
>
> In those cases, you usually know how to do it.
>
> You could memcpy() zero bits into a pointer.
Yes.
> You could assign (void*)(intptr_t)0 to a pointer.
No, 0, (intptr_t)0, and (void*)(intptr_t)0 are all null pointer
constants.
[...]
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2015-10-27 10:27 +1300 |
| Message-ID | <d97k5gFg0mfU4@mid.individual.net> |
| In reply to | #73898 |
supercat@casperkitty.com wrote: > On Monday, October 26, 2015 at 1:05:12 PM UTC-5, Keith Thompson wrote: >> There is. The expression 0 is of type int. In p==0, if p is of pointer >> type, the expression 0 is converted, via the special-case rule in N1570 >> 6.3.2.3p3, from int to the type of p. (This conversion is almost >> certainly done at compile time, though the standard doesn't say so.) > > In a system where (char*)x would yield a pointer to physical address x, > and where physical address zero was valid, but where (char*)0 [i.e. NULL] > was represented by a pointer with some physical address other than zero, > would there be any way of writing a pointer constant equal to physical > address zero? An argument for C adopting nullptr from C++? -- Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-10-26 15:15 -0700 |
| Message-ID | <lnvb9te0o4.fsf@kst-u.example.com> |
| In reply to | #73898 |
supercat@casperkitty.com writes:
> On Monday, October 26, 2015 at 1:05:12 PM UTC-5, Keith Thompson wrote:
>> There is. The expression 0 is of type int. In p==0, if p is of pointer
>> type, the expression 0 is converted, via the special-case rule in N1570
>> 6.3.2.3p3, from int to the type of p. (This conversion is almost
>> certainly done at compile time, though the standard doesn't say so.)
>
> In a system where (char*)x would yield a pointer to physical address x,
> and where physical address zero was valid, but where (char*)0 [i.e. NULL]
> was represented by a pointer with some physical address other than zero,
> would there be any way of writing a pointer constant equal to physical
> address zero?
No portable way -- but then pointer constants that refer to numeric
addresses are inherently non-portable anyway. A compiler could provide
some special-case way of representing address zero if it were useful.
>> > As for the very last part, I don't think so. Both p and q are null
>> > pointers of the same type. Whilst I agree that !(intptr_t)p might be
>> > 0, I can't see how can !q be anything other than 1.
>>
>> Agreed. (1-1) is a null pointer constant, and so is (intprt_t)(1-1)
>> (since casts are permitted in integer constant expressions). An integer
>> constant expression with the value 0 cast to any pointer type is a null
>> pointer constant, so (unsigned char*)(intptr_t)(1-1) is a null pointer
>> constant.
>
> I guess "1-1" wasn't sufficiently subtle for a compiler to miss that it was
> really a constant; C# distinguishes between literal zeroes and integer
> constants whose value happens to equal zero, but I guess C doesn't?
Why guess? N1570 6.3.2.3 defines null pointer constants. 6.6 defines
integer constant expressions. Read The Fine Manual.
> Would the value of (int)0.3 be considered an integer constant? What about
> (int)(1.0E+17+1.0-1.0E+17), whose value would depend upon how floating-point
> precision was handled?
N1570 6.6. Yes, it's possible to write an integer constant expression
whose value is implementation-defined. (CHAR_BIT is another example of
such an expression.)
> I sometimes wish the C Standard would define an intrinsic which would take
> a possibly-constant argument and yield a value equal to the argument but
> behave as though the value wasn't known until run-time since, especially in
> the embedded-systems world, it may be necessary to have various things take
> the same amount of time regardless of whether a particular argument is or
> is not a constant.
A separately compiled function that returns its argument might be
sufficient for some purposes.
>
>> A better example would be:
>>
>> unsigned char *p = 0;
>> const int not_a_constant zero = 0;
>> unsigned char *q = (unsigned char*)zero;
>>
>> The value of p is a null pointer. The value of q may or may not be.
>>
>> And converting a null pointer value to intptr_t may or may not yield 0.
>
> Are there any other cases in C where an expression which the compiler can
> recognize as being equal to zero, and an expression always happens to yield
> zero but isn't recognized as such, would both be valid but semantically
> different?
A compiler isn't required to recognize that the value of `zero` given
const int zero = 0;
is always 0, but I'd be surprised by a compiler that didn't do so.
> I wonder how much code would break if the Standard were to
> require that the argument to the cast must have one of a small number of
> literal forms (e.g. 0, 0L, etc.) rather than merely being any constant
> expression whose value happens to be zero?
I wonder how useful such a change would really be. If you want a
pointer value whose representation is all-bits-zero, define a pointer
object and call memset(). But I've never felt the need for such a
pointer value.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2015-10-26 16:16 -0700 |
| Message-ID | <cb09dac4-3bb7-4e05-bb20-a919d00d85e2@googlegroups.com> |
| In reply to | #73917 |
On Monday, October 26, 2015 at 5:16:07 PM UTC-5, Keith Thompson wrote: > supercat writes: > > In a system where (char*)x would yield a pointer to physical address x, > > and where physical address zero was valid, but where (char*)0 [i.e. NULL] > > was represented by a pointer with some physical address other than zero, > > would there be any way of writing a pointer constant equal to physical > > address zero? > > No portable way -- but then pointer constants that refer to numeric > addresses are inherently non-portable anyway. A compiler could provide > some special-case way of representing address zero if it were useful. Many CPU architectures are used on a variety of hardware configurations, and compilers are generally specialized per architecture, rather than per hardware configuration. Obviously a program which is designed for a system with various devices at different addresses will not be directly portable to other CPU platforms, but it would be nice if it could be reasonably portable among compilers for the same architecture. > > I guess "1-1" wasn't sufficiently subtle for a compiler to miss that it was > > really a constant; C# distinguishes between literal zeroes and integer > > constants whose value happens to equal zero, but I guess C doesn't? > > Why guess? N1570 6.3.2.3 defines null pointer constants. 6.6 defines > integer constant expressions. Read The Fine Manual. Sorry, by "I guess" I meant "I guess my memory of the distinctions among the various C-ish languages isn't perfect". > > Would the value of (int)0.3 be considered an integer constant? What about > > (int)(1.0E+17+1.0-1.0E+17), whose value would depend upon how floating-point > > precision was handled? > > N1570 6.6. Yes, it's possible to write an integer constant expression > whose value is implementation-defined. (CHAR_BIT is another example of > such an expression.) CHAR_BIT is a constant whose meaning can be known before a program begins execution. The value yielded by adding 1 to 1E+17 and then subtracting 1E17 from the result may vary depending upon the FPU configuration, and I believe some compilers have options to defer floating-point calculations until runtime for precisely that reason. > > I sometimes wish the C Standard would define an intrinsic which would take > > a possibly-constant argument and yield a value equal to the argument but > > behave as though the value wasn't known until run-time since, especially in > > the embedded-systems world, it may be necessary to have various things take > > the same amount of time regardless of whether a particular argument is or > > is not a constant. > > A separately compiled function that returns its argument might be > sufficient for some purposes. That would work, but I regard that as falling into the category of having to ask for something one doesn't want in the hopes of retaining the behavior one does--something I think should be minimized in a well-designed language. > > Are there any other cases in C where an expression which the compiler can > > recognize as being equal to zero, and an expression always happens to yield > > zero but isn't recognized as such, would both be valid but semantically > > different? > > A compiler isn't required to recognize that the value of `zero` given > const int zero = 0; > is always 0, but I'd be surprised by a compiler that didn't do so. Actually, there are a number of situations where it can be important that compilers not make such assumptions; one can argue that "volatile" should be used if e.g. a value in the executable will be patched between link time and execution, but if the value won't change at any other time using volatile would seem a little overkill, especially since it would cause the compiler to squawk any time the address is passed to something that doesn't expect a volatile-qualified pointer. In any case, though, that's not what I meant. If a system defines the value of (intptr)(char*)0 to be 0xDEADBEEF, then the value of (intptr)(char*)(expr) would be 0xDEADBEEF if (expr) is a compile-time constant zero but zero if (expr) is a non-compile-time-constant zero. Are there any other situations you can think of where an an expression would be valid if a sub-expression is a compile-time constant, and also be valid if it isn't, but would have different meanings in those two cases? > > I wonder how much code would break if the Standard were to > > require that the argument to the cast must have one of a small number of > > literal forms (e.g. 0, 0L, etc.) rather than merely being any constant > > expression whose value happens to be zero? > > I wonder how useful such a change would really be. If you want a > pointer value whose representation is all-bits-zero, define a pointer > object and call memset(). But I've never felt the need for such a > pointer value. You probably have never coded for a machine that put anything useful at address zero. One of the few places where the C Standard makes reference to the concept of a target architecture being something apart from the implementation is in the discussion of integer-to-pointer conversions, which are supposed to be done in a fashion unsurprising to someone familiar with the architecture. Having code work fine when configured to use the second parallel-I/O port (whose address is set to 0x0002 in a header file) but then break when changed to use the first (whose address is set to 0x0000) because the optimizer ripped it to shreds would not satisfy the "unsurprising" requirement. If the Standard provided that casting or coercing anything other than a single digit zero directly to a pointer would invoke Implementation-Deined behavior, and recommended that (char*)(intptr_t)0 should be interpreted according to the rules applicable to non-constant expressions yielding zero, that shouldn't break much code (compilers could include an option to interpret all forms of constant zero as the Standard used to require) but also make it easier to avoid "surprises" when using things that happen to use address zero.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-10-27 08:39 -0700 |
| Message-ID | <lna8r4e2wt.fsf@kst-u.example.com> |
| In reply to | #73920 |
supercat@casperkitty.com writes:
> On Monday, October 26, 2015 at 5:16:07 PM UTC-5, Keith Thompson wrote:
>> supercat writes:
>> > In a system where (char*)x would yield a pointer to physical address x,
>> > and where physical address zero was valid, but where (char*)0 [i.e. NULL]
>> > was represented by a pointer with some physical address other than zero,
>> > would there be any way of writing a pointer constant equal to physical
>> > address zero?
>>
>> No portable way -- but then pointer constants that refer to numeric
>> addresses are inherently non-portable anyway. A compiler could provide
>> some special-case way of representing address zero if it were useful.
>
> Many CPU architectures are used on a variety of hardware configurations,
> and compilers are generally specialized per architecture, rather than
> per hardware configuration. Obviously a program which is designed for
> a system with various devices at different addresses will not be directly
> portable to other CPU platforms, but it would be nice if it could be
> reasonably portable among compilers for the same architecture.
If you're willing to settle for "reasonably portable", just assume that
a null pointer is all-bits-zero. Add a runtime check to the beginning
of the program so the program dies if that's not the case.
>> > I guess "1-1" wasn't sufficiently subtle for a compiler to miss that it was
>> > really a constant; C# distinguishes between literal zeroes and integer
>> > constants whose value happens to equal zero, but I guess C doesn't?
>>
>> Why guess? N1570 6.3.2.3 defines null pointer constants. 6.6 defines
>> integer constant expressions. Read The Fine Manual.
>
> Sorry, by "I guess" I meant "I guess my memory of the distinctions among the
> various C-ish languages isn't perfect".
The rules for null pointer constants have not changed across C89/90,
C99, and C11. (C++ rules differ, but not in any way that's relevant to
the current discussion.)
>> > Would the value of (int)0.3 be considered an integer constant? What about
>> > (int)(1.0E+17+1.0-1.0E+17), whose value would depend upon how floating-point
>> > precision was handled?
>>
>> N1570 6.6. Yes, it's possible to write an integer constant expression
>> whose value is implementation-defined. (CHAR_BIT is another example of
>> such an expression.)
>
> CHAR_BIT is a constant whose meaning can be known before a program begins
> execution. The value yielded by adding 1 to 1E+17 and then subtracting
> 1E17 from the result may vary depending upon the FPU configuration, and I
> believe some compilers have options to defer floating-point calculations
> until runtime for precisely that reason.
(int)(1.0E+17+1.0-1.0E+17) is an integer constant expression. Its
evaluation cannot be deferred until runtime, at least not if it's used
in a context where a constant expression is required.
Its value can vary depending on various factors. Has this ever been a
problem for you? The only reason I can think of to use such an
expression is because you *want* its value to depend on the system's
floating-point characteristics.
[...]
>> > I wonder how much code would break if the Standard were to
>> > require that the argument to the cast must have one of a small number of
>> > literal forms (e.g. 0, 0L, etc.) rather than merely being any constant
>> > expression whose value happens to be zero?
>>
>> I wonder how useful such a change would really be. If you want a
>> pointer value whose representation is all-bits-zero, define a pointer
>> object and call memset(). But I've never felt the need for such a
>> pointer value.
>
> You probably have never coded for a machine that put anything useful at
> address zero.
No, I haven't.
> One of the few places where the C Standard makes reference to the concept
> of a target architecture being something apart from the implementation is
> in the discussion of integer-to-pointer conversions, which are supposed to
> be done in a fashion unsurprising to someone familiar with the architecture.
> Having code work fine when configured to use the second parallel-I/O port
> (whose address is set to 0x0002 in a header file) but then break when changed
> to use the first (whose address is set to 0x0000) because the optimizer
> ripped it to shreds would not satisfy the "unsurprising" requirement. If
> the Standard provided that casting or coercing anything other than a single
> digit zero directly to a pointer would invoke Implementation-Deined behavior,
> and recommended that
>
> (char*)(intptr_t)0
>
> should be interpreted according to the rules applicable to non-constant
> expressions yielding zero, that shouldn't break much code (compilers could
> include an option to interpret all forms of constant zero as the Standard
> used to require) but also make it easier to avoid "surprises" when using
> things that happen to use address zero.
Leaving the definition as it is won't break *any* code.
You propose changing the language definition to enable portable access
to address 0 on systems where a null pointer is not represented as
all-bits-zero. Do you have a real-world use case for this? If not, I
suggest not worrying about it.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2015-10-26 14:04 +0000 |
| Message-ID | <n0lbpc$op5$1@dont-email.me> |
| In reply to | #73851 |
On 26/10/15 13:21, fl wrote: > Hi, > > I saw coding such as: a=!a before. Today, when I write my code below, I find > if on_off_flag==0, on_off_flag will be '1' after > > on_off_flag = !on_off_flag; > > It is a surprise to me. I supposed it will be 0xFFFF,FFFF for integer > on_off_flag > > '!' is an inverse operator or not? It's the logical inverse. !anynonzerovalue is 0, and !0 is 1, by definition. If you want bitwise inverse, use ~ and be careful. -- Richard Heathfield Email: rjh at cpax dot org dot uk "Usenet is a strange place" - dmr 29 July 1999 Sig line 4 vacant - apply within
[toc] | [prev] | [next] | [standalone]
| From | Geoff <geoff@invalid.invalid> |
|---|---|
| Date | 2015-10-26 09:50 -0700 |
| Message-ID | <9ijs2b1kiqdr27c6h4t90v9t6fka9hve0p@4ax.com> |
| In reply to | #73851 |
On Mon, 26 Oct 2015 06:21:35 -0700 (PDT), fl <rxjwg98@gmail.com>
wrote:
>Hi,
>
>I saw coding such as: a=!a before. Today, when I write my code below, I find
>if on_off_flag==0, on_off_flag will be '1' after
>
> on_off_flag = !on_off_flag;
>
>It is a surprise to me. I supposed it will be 0xFFFF,FFFF for integer
> on_off_flag
>
>'!' is an inverse operator or not?
>
>
>Thanks,
>
>
>static int on_off_flag = 0;
>static int on_off_counter = 0;
>
> on_off_counter++;
> if (on_off_counter == 1000){
> on_off_counter = 0;
> on_off_flag = !on_off_flag;
It is not an inversion operator, it's the logical negation operator
and it only evaluates to 1 or 0.
In hardware terms this represents a toggle. The result of the !
operator evaluates to 0 if its operand is not zero and 1 if the
operand is 0. In this case, the on_off_flag will only contain either 1
or 0. This code appears to be toggling on_off_flag for every 1000
counts of the on_off_counter. If you had initialized on_off_flag to
another value, say 5, the ! operator would change this to 0 and when
the on_off_flag = !on_off_flag is encountered again, it would change
the 0 to 1.
In embedded systems we'd call something similar to the code above a
pulse stretcher. The on_off_counter would be incremented in response
to some stimulus like a pulse train, 1000 Hz for example, and the
on_off_flag might be used to set the state of a bit that controls an
LED. For a 1000 Hz pulse train the LED would blink once per second.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web