> I don't have the text of C99 here but from the earlier C89 standard:
>
> 6.3.4
> Conversions that involve pointers (other than as permitted by the
> constraints of 6.3.16.1) shall be specified by means of an explicit cast
>
> and in 6.3.16.1 Simple Assignment
> Constraints
> One of the following shall hold:
> ...
> - both operands are pointers to qualified or unqualified versions of
> compatible types
> - one operand is a pointer to an object or incomplete type and the other
> is a pointer to a qualified or unqualified version of void ...
> - the left operand is a pointer and the right is a null pointer constant
Now the question is: do these constraints apply before, or after the
semantics of 6.3.16.1 (C99: 6.5.16.1) have been taken care of? These
semantics are:
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.
The conversion of an integer to a pointer is explicitly allowed earlier
(C99: 6.3.2.3p5). So once that's happened, we're looking at an
assignment among pointers to compatible types, and all's fine.
> The Rationale from both C89 and C99 state that:
>
> "Since pointers and integers are now considered incommensurate, the only
> integer value that can be safely converted to a pointer is a constant
> expression with the value 0. The result of converting any other integer
> value, including a non-constant expression with the value 0, to a
> pointer is implementation-defined."
It's implementation-defined, and thus not "safe". But that's not the
same as being an error. It means that the program isn't fully
compliant, i.e. it won't be portable.
> So it sounds like a conforming implementation is not required to accept
> an assignment expression where the left-hand side is a pointer type and
> the right-hand side is an integer type without an explicit cast.
I don't see how that follows from the quoted definitions. Please note
that "implementation-defined result" does _not_ include a compiler
refusing to translate the source.
>
Reply by CBFalconer●July 5, 20082008-07-05
Hans-Bernhard Br�ker wrote:
> CBFalconer wrote:
>> Hans-Bernhard Br�ker wrote:
>
>>> I'll call. Show why exactly this would be an error. And no,
>>> examples of compilers that refuse to accept this don't count as
>>> evidence.
>
>> Because the 'address of PORTD' isn't a valid pointer in standard
>> C.
>> An address or pointer can involve all sorts of things, such as
>> disks, tapes, segments, whatever. If your system has provisions
>> to accept such things and convert them to 'pointers' then that
>> provision is peculiar to that system. It is NOT portable.
>
> Yes. But C does have implicit conversions from integers to pointers.
> So, while it's not certainly not portable, it's not strictly an error
> either.
Which is what I said, in one form or another, and which you
snipped. I have restored the 2nd, 3rd, and 4th sentences of my
message above.
--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
>CBFalconer wrote:
>> Hans-Bernhard Br�ker wrote:
>
>>> I'll call. Show why exactly this would be an error. And no,
>>> examples of compilers that refuse to accept this don't count as
>>> evidence.
>
>> Because the 'address of PORTD' isn't a valid pointer in standard
>> C.
>
>Yes. But C does have implicit conversions from integers to pointers.
>So, while it's not certainly not portable, it's not strictly an error
>either.
I don't have the text of C99 here but from the earlier C89 standard:
6.3.4
Conversions that involve pointers (other than as permitted by the
constraints of 6.3.16.1) shall be specified by means of an explicit cast
and in 6.3.16.1 Simple Assignment
Constraints
One of the following shall hold:
...
- both operands are pointers to qualified or unqualified versions of
compatible types
- one operand is a pointer to an object or incomplete type and the other
is a pointer to a qualified or unqualified version of void ...
- the left operand is a pointer and the right is a null pointer constant
The Rationale from both C89 and C99 state that:
"Since pointers and integers are now considered incommensurate, the only
integer value that can be safely converted to a pointer is a constant
expression with the value 0. The result of converting any other integer
value, including a non-constant expression with the value 0, to a
pointer is implementation-defined."
So it sounds like a conforming implementation is not required to accept
an assignment expression where the left-hand side is a pointer type and
the right-hand side is an integer type without an explicit cast.
--
Rich Webb Norfolk, VA
Reply by ●July 5, 20082008-07-05
CBFalconer wrote:
> Hans-Bernhard Br�ker wrote:
>> I'll call. Show why exactly this would be an error. And no,
>> examples of compilers that refuse to accept this don't count as
>> evidence.
> Because the 'address of PORTD' isn't a valid pointer in standard
> C.
Yes. But C does have implicit conversions from integers to pointers.
So, while it's not certainly not portable, it's not strictly an error
either.
Reply by CBFalconer●July 4, 20082008-07-04
Hans-Bernhard Br�ker wrote:
> Jack Klein wrote:
>> Frank Buss <fb@frank-buss.de> wrote
>>
>>> INT16* port_d = (INT16*) [put address of PORTD here];
>>>
>>> In C++ not adding a cast would be an error.
>>
>> It would be an error in C as well.
>
> I'll call. Show why exactly this would be an error. And no,
> examples of compilers that refuse to accept this don't count as
> evidence.
Because the 'address of PORTD' isn't a valid pointer in standard
C. An address or pointer can involve all sorts of things, such as
disks, tapes, segments, whatever. If your system has provisions to
accept such things and convert them to 'pointers' then that
provision is peculiar to that system. It is NOT portable.
--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Reply by ●July 4, 20082008-07-04
Jack Klein wrote:
> On Thu, 3 Jul 2008 21:51:39 +0200, Frank Buss <fb@frank-buss.de> wrote
>> INT16* port_d = (INT16*) [put address of PORTD here];
>> In C++ not adding a cast would be an error.
> It would be an error in C as well.
I'll call. Show why exactly this would be an error. And no, examples
of compilers that refuse to accept this don't count as evidence.
Reply by ChrisQ●July 4, 20082008-07-04
Thomas Magma wrote:
>>> ... I'm trying to find the most efficient way to save a 8-bit
>>> signed value found on the LSByte of PORTD to a CHAR. That is, the
>>> lower byte of PORTD contains a signed integer that is 8-bits
>>> wide and I need to save it to a CHAR data type. I don't care what
>>> is on the upper byte of PORTD.
>>
>> Just read the value and assign it to a char variable. Assuming you
>> do not need to do anything special to access the port:
>>
>> #define INT16 [put right type here]
>>
>> INT16 * port_d = [put address of PORTD here]; char c;
>>
>> ... c = *port_d;
Better still: c = (char) *port_d;
It may work, but you may get a warning. Always using a cast sends
a hint to the compiler and makes it clear when reading the code what is
actually being done. To be absolutely correct you should have a (const
*) when loading the absolute address and cast this to the pointer type
as well.
This is the sort of construct I usually use:
volatile U16 *pu16RegisterPtr = (U16 * const) REGISTER_ADDRESS;
Got this originally from Harbison & Steele and it seems to be correct.
The volatile keyword is telling the compiler that no part of the
expression should be changed or optimised in any way, while the const
keyword tells the compiler that this is, as expected a fixed value.
Chris
>
Reply by Frank Buss●July 4, 20082008-07-04
Jack Klein wrote:
> On Thu, 3 Jul 2008 21:51:39 +0200, Frank Buss <fb@frank-buss.de> wrote
>>
>> You should add a cast to avoid compiler warnings for C compilers:
>>
>> INT16* port_d = (INT16*) [put address of PORTD here];
>>
>> In C++ not adding a cast would be an error.
>
> It would be an error in C as well.
On Thu, 3 Jul 2008 21:51:39 +0200, Frank Buss <fb@frank-buss.de> wrote
in comp.arch.embedded:
> Roberto Waltman wrote:
>
> > #define INT16 [put right type here]
>
> You should use typedef instead of #define
>
> > INT16 * port_d = [put address of PORTD here];
>
> You should add a cast to avoid compiler warnings for C compilers:
>
> INT16* port_d = (INT16*) [put address of PORTD here];
>
> In C++ not adding a cast would be an error.
> Thanks Roberto, I guess this would make sense if the data representation of
> the dsPIC33 using the C30 compiler was stored in little endian format. Do
> you know if it is for sure?
This would be a problem, if you access a union or cast the int* to char*,
but if you first read the int* and then assign it to an char, endian
doesn't matter, the lower 8 bits are used all the time, which is what you
asked for. Of course, if you read the 16 bit value from PORTD, endian could
be a problem.
--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de,http://www.it4-systems.de