EmbeddedRelated.com
Forums

Strange IAR warning Pe550

Started by Albert Bartoszko December 19, 2003
Hi,

>
> This perfectly mimics (*(void(*)())ADDRESS+ INTEGER)() with something
> mortals can unsertand and it doesn't mean anything--it's adding a number
> of a function,

No, because it's simply adding INTEGER to the pointer. That is specified
in the chapter "Additive operators" (6.5.6).
You can also write

for (i=0;i<INTEGER;i++)
pointer++;

The GNU compiler is right.

Rolf F.

Beginning Microcontrollers with the MSP430

Rolf,

> > This perfectly mimics (*(void(*)())ADDRESS+ INTEGER)() with
> something
> > mortals can unsertand and it doesn't mean anything--it's adding a
> > number of a function,
>
> No, because it's simply adding INTEGER to the pointer.

No, it's not. You're dereferencing a pointer to a function and then
adding to that function:

(void(*)())ADDRESS - pointer to a function.

*(void(*)())ADDRESS - dereference a pointer to a function -- giving a
function object.

*(void(*)())ADDRESS + INTEGER - a function object plus an constant --
undefined.

> That
> is specified
> in the chapter "Additive operators" (6.5.6).

No, you are incorrect. You are adding to a function object, not a
pointer to a function. I picked this apart for you before, and
reiterate it above. The dereference of a pointer to a function gets you
a function object that you cannot add to.

> You can also write
>
> for (i=0;i<INTEGER;i++)
> pointer++;

I'm sure you can. But that's not what you asked for.

> The GNU compiler is right.

No, you are wrong. Whatever the GNU compiler does, it does. That
doesn't make it right nor you correct by implication.

If I compile the above with MS VC:

t.c(5) : error C2296: '+' : illegal, left operand has type 'void
(__cdecl *)()'

Or with CrossWorks:

c:/tmp/t.c(5): error E2117: operands of '+' have incompatible types
'int' and 'void (*)()'

Or with Archelon's compiler:

(*(void(*)())x+ 1)();
|
"t.c", line 5: Unknown size

Or with HI-TECH C:

t.c: foo()
5: (*(void(*)())x+ 1)();
type conflict ^

Both Borland C and Watcom C issue the same style of error. I could go
on. GNU C is in the minority of one here. You can't tell me that all
our compilers are wrong when I've pointed out your error and have
provided examples of other compilers that correctly diagnose the error.

If you can tell me where in the ANSI standard that you can add an
integer to a function (note: not a FUNCTION POINTER), I'll but you a
beer. At present you've shown where you can add an integer and a
pointer, but that's not what your source code shows.

-- Paul.
Paul,

>>That
>>is specified
>>in the chapter "Additive operators" (6.5.6).
>>
>>
>
>No, you are incorrect. You are adding to a function object, not a
>pointer to a function. I picked this apart for you before, and
>reiterate it above. The dereference of a pointer to a function gets you
>a function object that you cannot add to.
>
>

you are right that it looks like adding to a function object but that's
only one possible interpretation which is wrong in this case (because
there is another interpretation which is right).
In the standard you can find that an address constant can be created
implicitly by the use of an expression of function type (chapter
"Constant expressions", 6.6).
So *(void(*)())x+ INTEGER is simply adding a constant and an integer.

Rolf F.
Rolf,

> >No, you are incorrect. You are adding to a function object, not a
> >pointer to a function. I picked this apart for you before, and
> >reiterate it above. The dereference of a pointer to a function gets
> >you a function object that you cannot add to.
> >
> >
> you are right that it looks like adding to a function object
> but that's
> only one possible interpretation which is wrong in this case (because
> there is another interpretation which is right).
> In the standard you can find that an address constant can be created
> implicitly by the use of an expression of function type (chapter
> "Constant expressions", 6.6).
> So *(void(*)())x+ INTEGER is simply adding a constant and an integer.

Both casts and dereferences do not give rise to constant expressions, so
section 6.6 does not apply.

Section 6.6 states "A constant expression can be evaluated during
translation rather than runtime, and accordingly may be used in any
place that a constant may be." It goes on to say "The array-subscript
[] and member-access . and -> operators, the address & and indirection *
unary operators, and pointer casts may be used in the creation of an
address constant, but <B> the value of an object shall not be accessed
by use of these operators.</B>".

Your expression can't be evaluated at anything other than runtime. The
* is a dereferenc that is disallowed by the second clause presented.

So, you're still wrong. ;-) I'm going to sign off and not say anything
more, other than the GNU compiler, if it compiles the original, is
incorrect when measured against the ANSI standard.

-- Paul.
Rolf,

> > Both casts and dereferences do not give rise to constant
> expressions,
> > so section 6.6 does not apply.
>
> i don't agree with that meaning but indepently from this the standard
> does not forbid it with variables.
> The ANSI standard constraints (in chapter "Additive
> operators") do only
> say "shall" not "must".
> So the gcc can do more than he must but that is compatible with the
> standard.

Wrong again. From section 4.1, "In this International Standard,
''shall'' is to be interpreted as a requirement on an implementation or
on a program; conversely, ''shall not'' is to be interpreted as a
prohibition." Thus shall == must. If the standard says "shall
backfire", it really, really, must backfire to claim ANSI conformance.

-- Paul.
Paul,

> Both casts and dereferences do not give rise to constant expressions, so
> section 6.6 does not apply.

i don't agree with that meaning but indepently from this the standard
does not forbid it with variables.
The ANSI standard constraints (in chapter "Additive operators") do only
say "shall" not "must".
So the gcc can do more than he must but that is compatible with the
standard.

Rolf F.
Paul,

>>i don't agree with that meaning but indepently from this the standard
>>does not forbid it with variables.
>>The ANSI standard constraints (in chapter "Additive
>>operators") do only
>>say "shall" not "must".
>>So the gcc can do more than he must but that is compatible with the
>>standard.
>>
>>
>
>Wrong again. From section 4.1, "In this International Standard,
>''shall'' is to be interpreted as a requirement on an implementation or
>on a program; conversely, ''shall not'' is to be interpreted as a
>prohibition." Thus shall == must. If the standard says "shall
>backfire", it really, really, must backfire to claim ANSI conformance.
>

if you read the standard pedantic you have to use the gcc option
"-pedantic" and then you get your warning from gcc:

> gcc -ansi -pedantic -o foo foo.c
foo.c:20: warning: pointer to a function used in arithmetic

If you say gcc what you want you get it ;-)
I think it's not enough to use "-ansi" because that gcc feature will
(may) be in the next version of the ANSI C standard.

Rolf F.
On Fri, 19 Dec 2003 12:40:16 +0100, you wrote:

><snip>
>when compile timerA interrupt function with body:
>------------------------
>static void ((* const TA_vector[])(void)) = {
> timerA_fail, // no interrupt
> timerA_fail, // TACCR1
> timerA_fail, // TACCR2
> timerA_fail, // unexpected
> timerA_fail, // unexpected
> timerA_overflow // TA overflow
> };
>
> ((void (*)(void))((char *)TA_vector + TAIV))();
>--------------------------
>
>Generated code is as expected.

Are you just trying to call one of several functions in a list,
depending on TAIV? If so, the syntax is usually:

TA_vector[TAIV >> 1]();

or,

(*TA_vector[TAIV >> 1])();

or,

(*(TA_vector + (TAIV >> 1)))();

I believe all of those are equivalent forms of the same
semantic, which is calling a function pointed to by the TAIV'th
entry in the TA_vector array of function pointers.

Your line:

((void (*)(void))((char *)TA_vector + TAIV))();

Appears very similar, of course. But essentially this is saying
that you want to call code __AT__ the address in the table, not
through the address listed in the table. It does so because you
are casting a "pointer to a function pointer" to a "function
pointer," instead. So a C compiler should probably then just
try and call the indicated address, which is a data address
pointing some place inside your vector table (where data is
sitting, and not code.)

You could use:

(*(void(**)(void))((char*)TA_vector+TAIV))();

I think that would fix up where you were going with all those
casts, without judging the whys of it. You might want to,
however, keep the const nature of things and restate this as:

(*(void(*const*)(void))((char*)TA_vector+TAIV))();

Ander's suggestion of:

typedef void fp(void);
((fp *)*(int *) ((char *)TA_vector + TAIV))();

is about the same thing when an (int*) is the same size and
representation as a function pointer. But it does appear to
depend on the fact that a non-zero int can be legally converted
to a non-NULL function pointer. Of course, your code also
assumes that the sizes are at least the same, using the (char*)
and the mapping of TAIV, so I'd guess this isn't any further
imposition. But a compiler may be permitted to convert a
non-zero integer into random garbage before converting it to a
function pointer, as I think the specification doesn't require
the same alignment restrictions or pretty much anything else on
that matter. (The only integer I'm aware of which must make
sense is when casting a zero, I think. But I could be wrong
about that.)

It makes sense to me to write it as:

TA_vector[TAIV >> 1]();

At the worst, a smart compiler will itself "know" that the size
of a function pointer is two bytes and that it needs to shift
(TAIV>>1) back up, as in (TA_vector+((TAIV>>1)<<1)), so that
this results in a masking operation of the least significant
bit, only. Okay. So a good compiler will get you one BIC
instruction inserted in to clear a bit you know is already
cleared. Unless things are that critical, you can probably
afford it. Anders' suggestion would avoid the bit clear
operation, though, at the expense of using a syntax which takes
a moment to follow.

Jon