Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Re: Getting started with AVR and C (http://www.velocityreviews.com/forums/t954807-re-getting-started-with-avr-and-c.html)

Ivan Shmakov 11-24-2012 09:18 PM

Re: Getting started with AVR and C
 
>>>>> Robert Roland <fake@ddress.no> writes:

[Cross-posting to news:comp.lang.c, in the hope that someone
could provide more suggestions, or correct me on C.]

[...]

> 2. Where do I start learning C? Is there a good online tutorial
> somewhere? I'd also be willing to buy a book. Is there one that
> stands out as the best?


Frankly, I don't quite understand how did I learn C myself.
FWIW, there were hardly any good book on that that I've read.

Two aspects of C are probably to be highlighted:

* first of all, unlike some other, and higher-level, languages
(like Pascal, BASIC, etc.), C has a very concise set of
syntactic constructs; most of the power lies in libraries, and
should you end up using AVR Libc, be sure to check its
reference manual [1] (it isn't as good as the GNU C Library
manual I'm using for the most time I need information on C,
but it's still useful);

* the C constructs tend to be translated into assembly in a
rather straightforward manner (unless advanced optimization is
involved, that is); consider, e. g.:

int8_t i; /* not necessarily translated; may force
the compiler to "allocate" a register
(say, r7), or a memory cell */
i = 3; /* ldi r7, 3 */
i += 2; /* adi r7, 2 */
i++; /* inc r7 */
if (i < 9) { /* cpi r7, 9 ; brge else_a */
int8_t j = 5; /* ldi r8, 5 */
while (j >= 3) { /* while_a:
cpi r8, 3
brlt end_while_a */
PORTB ^= 1; /* in r9, PORTB
eoi r9, 1
out PORTB, r9 */
} /* jmp while_a
end_while_a: */
} /* else_a: */

Not to undermine its value, but as could be seen (I hope) from
this example, for the most part, C only manages registers and
memory (including function calling conventions) while the rest
of its /syntax/ is comparable to that of a library of assembly
language macros of some sort.

A cheat sheet for most of the C operators would probably be
something like the following (where a, b, c, ... are either
numeric literals, variable identifiers, or expressions.) Note
that whenever all the operands are integer, an integer operation
is performed. (So, 7 / 3 is 2.) The result is as wide as the
widest of the operands. (So, i + j is 0 if i is 255, j is 1,
and both are declared to be of the 8-bit unsigned integer
uint8_t type.)

Operation Value Side-effect

Operations free of side-effects

+ a a
- a - a
* a the value of the memory cell at address
a
& a the address of a (must be an "l-value")
~ a bitwise negated a
! a 1 if a is 0,
0 otherwise
a, b b
NB: a is evaluated first, its result discarded.
a + b a + b
a - b a - b
a * b a b
a / b a / b (quotient of)
a % b remainder of a / b
a & b a (bitwise and) b
a | b a (bitwise or) b
a ^ b a (bitwise exclusive or) b
a << b a times 2 ^b (shift left)
a >> b a times 2 ^(-b) (shift right)
a < b 1 if a is less than b,
0 otherwise
a > b 1 if a is greater than b,
0 otherwise
a == b 1 if a is equal to b,
0 otherwise
a <= b 1 if a is less than or equal to b,
0 otherwise
a >= b 1 if a is greater than or equal to b,
0 otherwise

Conditional operations

a && b a is evaluated;
if a is non-zero, the value is b;
otherwise, the value is 0, while b is
not evaluated at all
a || b a is evaluated;
if a is zero, the value is b;
otherwise, the value is a, while b is
not evaluated at all
a ? b : c a is evaluated first;
if a is non-zero, the value is b;
otherwise, the value is c;
the other ("unused") expression is not
evaluated

Operations with side-effects

NB: a must be an "l-value"
a++ a a set to a + 1
a-- a a set to a - 1
++a a + 1 a set to value
--a a - 1 a set to value
a = b b a set to value
a += b a + b a set to value
a -= b a - b a set to value
a *= b a b a set to value
a /= b a / b a set to value
a &= b a (bitwise and) b a set to value
a |= b a (bitwise or) b a set to value
a ^= b a (bitwise xor) b a set to value
a <<= b a times 2 ^b a set to value
a >>= b a times 2 ^(-b) a set to value

Naturally, both "=" and "," can be "nested", thus:

for (a = b = 0, c = 5; c > 0; a++, b++, c--) {
/* ... */
}

To note is that the for () <statement> form is just a short-hand
for a specific while () loop. For instance, the for ()
statement above can be rewritten as follows:

a = b = 0, c = 5;
while (c > 0) {
/* ... */
a++, b++, c--;
}

Thus, the only convenience of for () is that it allows for the
"at-the-end-of-the-loop" part to be written above the loop body
itself (i. e., together with the loop condition.)

One more thing to note is that there're two basic contexts: the
statement context, and the expression context. The switch from
the former to the latter usually takes place in obvious places,
while it isn't possible (in standard C; AFAIK) to switch from
the latter to the former. E. g.:

/* statement context */
while (a < 5 /* expression context */) {
/* statement context */
b = 4 /* expression context */ ;
/* NB: cannot switch back to the statement context, like: */
/* c = while (b > 0) { /* ... */ } ; */
}

As one may need a conditional operator in either context, C has
both the ?:-operator (see above), and (perhaps a more
conventional) if ():

if (a) {
/* the code here will be executed iff a is non-zero */
} else {
/* the code here will be executed otherwise */
}

The { }-grouping is only necessary if more than one statement is
needed as the body; otherwise, it may be elided, like:

if (a) b = c;

This allows for convenient nesting, like:

if (a) {
/* ... */
} else if (b) {
/* ... */
} else {
/* ... */
}

A similar idiom is possible for the ?:-operator just as well.
Consider, e. g.:

a = (b ? c
: d ? e
: f);

which is not dissimilar to more verbose (and error-prone):

if (b) {
a = c;
} else if (d) {
a = e;
} else {
a = f;
}

An example program for an AVR could be as follows.

#include <avr/io.h> /* for PORTB, DDRB, etc. */
#include <util/delay.h> /* for _delay_ms () */

/* global variable declarations; not necessary in this example */

static void
blink_led (void)
{
PORTB ^= (1 << PB0); /* toggle PB0 */
_delay_ms (500); /* wait for 0.5 s */
PORTB ^= (1 << PB0); /* toggle PB0 again */
_delay_ms (500); /* wait for 0.5 s more */
}

/* the main () function is the conventional program's entry point */
int
main ()
{
/* set up PB0 for output, all the other tri-stated */
DDRB = (DDRB0 << 1);

/* enter infinite loop */
while (1) {
/* call our function */
blink_led ();
}

/* never reached */
return 0;
}

For sure, there's over than a dozen of individual syntactic
constructs more (and then there's a handful or so of the
preprocessor #-directives, too), but I hope that with the above,
reading the sources would become a bit easier task.

[1] http://www.nongnu.org/avr-libc/user-manual/

--
FSF associate member #7257

Richard Damon 11-24-2012 10:09 PM

Re: Getting started with AVR and C
 
On 11/24/12 4:18 PM, Ivan Shmakov wrote:
> for (a = b = 0, c = 5; c > 0; a++, b++, c--) {
> /* ... */
> }
>
> To note is that the for () <statement> form is just a short-hand
> for a specific while () loop. For instance, the for ()
> statement above can be rewritten as follows:
>
> a = b = 0, c = 5;
> while (c > 0) {
> /* ... */
> a++, b++, c--;
> }


This is not completely correct in general. For instance if you replace
the /* ... */ with continue; then the for loop jumps from the continue
statement to the increment clause of the loop, but the while loop jumps
to the beginning of the loop body (causing an infinite loop).

Ben Bacarisse 11-24-2012 10:12 PM

Re: Getting started with AVR and C
 
Ivan Shmakov <oneingray@gmail.com> writes:

>>>>>> Robert Roland <fake@ddress.no> writes:

>
> [Cross-posting to news:comp.lang.c, in the hope that someone
> could provide more suggestions, or correct me on C.]


I'll have a look...

<snip>
> [...] Note
> that whenever all the operands are integer, an integer operation
> is performed. (So, 7 / 3 is 2.) The result is as wide as the
> widest of the operands. (So, i + j is 0 if i is 255, j is 1,
> and both are declared to be of the 8-bit unsigned integer
> uint8_t type.)


No the return will be of type int in that case. The rules are rather
involved, but the gist of it is that everything "smaller" than an int
gets converted to an int. When the types involved are int or larger,
both get converted to the larger type. Mixed signed and unsigned types
generally result in the signed operand being converted to the type of
the unsigned operand (after promotion).

The standard takes pages to describe these rules, so there is no way I
can summarise them here with 100% accuracy. Given that you summary is
not short, it might be worth including them. You'd then need to say
to which operators they apply (for example they don't apply to the
shift operators).

> Operation Value Side-effect
>
> Operations free of side-effects
>
> + a a
> - a - a
> * a the value of the memory cell at address
> a


This rather reinforces a view of C are lower-level than it really is.
The result might not square with how people think of a memory cell (for
example, if a is a function pointer, or when it is pointer to a struct
type).

> & a the address of a (must be an "l-value")
> ~ a bitwise negated a
> ! a 1 if a is 0,
> 0 otherwise


You don't talk about array the indexing operator, [], not the function
call operator, (). there are others, too, like sizeof and cast
operators. In tabular summary, I don't think it hurts to be complete.

> a, b b
> NB: a is evaluated first, its result discarded.
> a + b a + b
> a - b a - b
> a * b a b
> a / b a / b (quotient of)
> a % b remainder of a / b
> a & b a (bitwise and) b
> a | b a (bitwise or) b
> a ^ b a (bitwise exclusive or) b
> a << b a times 2 ^b (shift left)
> a >> b a times 2 ^(-b) (shift right)


These ones are tricky because of all the corner cases (a shift equal or
greater than the operand size, a shift of a bit into the sign position,
a right shift of a negative quantity). In a summary like this may just
a footnote to "beware".

> a < b 1 if a is less than b,
> 0 otherwise
> a > b 1 if a is greater than b,
> 0 otherwise
> a == b 1 if a is equal to b,
> 0 otherwise
> a <= b 1 if a is less than or equal to b,
> 0 otherwise
> a >= b 1 if a is greater than or equal to b,
> 0 otherwise
>
> Conditional operations
>
> a && b a is evaluated;
> if a is non-zero, the value is b;
> otherwise, the value is 0, while b is
> not evaluated at all
> a || b a is evaluated;
> if a is zero, the value is b;
> otherwise, the value is a, while b is
> not evaluated at all
> a ? b : c a is evaluated first;
> if a is non-zero, the value is b;
> otherwise, the value is c;
> the other ("unused") expression is not
> evaluated
>
> Operations with side-effects
>
> NB: a must be an "l-value"


Yes and it might help to say which of the expression yield and lvalue.
For example, you can write ++*a but not ++!a. It's might well be
obvious, but you could have a column for "is an lvalue".

> a++ a a set to a + 1
> a-- a a set to a - 1
> ++a a + 1 a set to value
> --a a - 1 a set to value
> a = b b a set to value
> a += b a + b a set to value
> a -= b a - b a set to value
> a *= b a b a set to value
> a /= b a / b a set to value


a %=b is missing. But maybe it's better to generalise: a op= b and say what
op can be?

> a &= b a (bitwise and) b a set to value
> a |= b a (bitwise or) b a set to value
> a ^= b a (bitwise xor) b a set to value
> a <<= b a times 2 ^b a set to value
> a >>= b a times 2 ^(-b) a set to value
>
> Naturally, both "=" and "," can be "nested", thus:


In most tables of operators, you see both priority and associativity.
Assign ment does not yield an lvalue, so a = b = 0 only works because =
associates to the right a = (b = 0). Most C binary operators associate
to the left (i.e. a - b - c means (a - b) - c).

You could make a really rich summary table that shows priority,
associativity, whether the expression denotes an lvalue and what happens
to the operands (are they just promoted as for the shift operands or are
the "usual arithmetic conversions" applied as for + and *). I can see
why you would want to avoid too much detail in a simple explanation like
this, but it does seem like a useful thing to do.

> for (a = b = 0, c = 5; c > 0; a++, b++, c--) {
> /* ... */
> }
>
> To note is that the for () <statement> form is just a short-hand
> for a specific while () loop. For instance, the for ()
> statement above can be rewritten as follows:
>
> a = b = 0, c = 5;
> while (c > 0) {
> /* ... */
> a++, b++, c--;
> }


Provided that /* ... */ contains no continue statements (except as part
of a nested statement of course).

> Thus, the only convenience of for () is that it allows for the
> "at-the-end-of-the-loop" part to be written above the loop body
> itself (i. e., together with the loop condition.)
>
> One more thing to note is that there're two basic contexts: the
> statement context, and the expression context. The switch from
> the former to the latter usually takes place in obvious places,
> while it isn't possible (in standard C; AFAIK) to switch from
> the latter to the former. E. g.:
>
> /* statement context */
> while (a < 5 /* expression context */) {
> /* statement context */
> b = 4 /* expression context */ ;
> /* NB: cannot switch back to the statement context, like: */
> /* c = while (b > 0) { /* ... */ } ; */
> }


A sad omission for fans of BCPL!

> As one may need a conditional operator in either context, C has
> both the ?:-operator (see above), and (perhaps a more
> conventional) if ():
>
> if (a) {
> /* the code here will be executed iff a is non-zero */
> } else {
> /* the code here will be executed otherwise */
> }
>
> The { }-grouping is only necessary if more than one statement is
> needed as the body; otherwise, it may be elided, like:
>
> if (a) b = c;
>
> This allows for convenient nesting, like:
>
> if (a) {
> /* ... */
> } else if (b) {
> /* ... */
> } else {
> /* ... */
> }
>
> A similar idiom is possible for the ?:-operator just as well.
> Consider, e. g.:
>
> a = (b ? c
> : d ? e
> : f);
>
> which is not dissimilar to more verbose (and error-prone):


You will find disagreement about that parenthetical remark in comp.lang.c.

> if (b) {
> a = c;
> } else if (d) {
> a = e;
> } else {
> a = f;
> }


<snip example>
--
Ben.

Nick Keighley 11-25-2012 01:41 PM

Re: Getting started with AVR and C
 
On Nov 24, 9:18*pm, Ivan Shmakov <oneing...@gmail.com> wrote:
> >>>>> Robert Roland <f...@ddress.no> writes:

>
> * * * * [Cross-posting to news:comp.lang.c, in the hope that someone
> * * * * could provide more suggestions, or correct me on C.]
>
> [...]
>
> *> 2. Where do I start learning C? *Is there a good online tutorial
> *> somewhere? *I'd also be willing to buy a book. *Is there one that
> *> stands out as the best?
>
> * * * * Frankly, I don't quite understand how did I learn C myself.
> * * * * FWIW, there were hardly any good book on that that I've read.


K&R?

Rosario1903 11-27-2012 09:21 AM

Re: Getting started with AVR and C
 
On Sun, 25 Nov 2012 04:18:32 +0700, Ivan Shmakov <oneingray@gmail.com>
wrote:


> int8_t i; /* not necessarily translated; may force
> the compiler to "allocate" a register
> (say, r7), or a memory cell */
> i = 3; /* ldi r7, 3 */
> i += 2; /* adi r7, 2 */
> i++; /* inc r7 */
> if (i < 9) { /* cpi r7, 9 ; brge else_a */
> int8_t j = 5; /* ldi r8, 5 */
> while (j >= 3) { /* while_a:
> cpi r8, 3
> brlt end_while_a */
> PORTB ^= 1; /* in r9, PORTB
> eoi r9, 1
> out PORTB, r9 */
> } /* jmp while_a
> end_while_a: */
> } /* else_a: */


for me

> i = 3; /* ldi r7, 3 */
> i += 2; /* adi r7, 2 */
> i++; /* inc r7 */


are the same
one call "r7", "i" and are the same

for the remain i possibly prefer my macroized
part of the right side

than in the right side one can controll better the stack...

>[1] http://www.nongnu.org/avr-libc/user-manual/



Ivan Shmakov 11-28-2012 05:54 AM

statement / expression contexts in C
 
>>>>> Dave Nadler <drn@nadler.com> writes:
>>>>> On Saturday, November 24, 2012 5:12:09 PM UTC-5, Ben Bacarisse wrote:


[Cross-posting to news:comp.lang.c, and dropping
news:comp.arch.embedded from Followup-To:.]

[...]

>>> /* statement context */
>>> while (a < 5 /* expression context */) {
>>> /* statement context */
>>> b = 4 /* expression context */ ;
>>> /* NB: cannot switch back to the statement context, like: */
>>> /* c = while (b > 0) { /* ... */ } ; */
>>> }


>> A sad omission for fans of BCPL!


> Wow ! I last programmed in BCPL in late 1977. And I still miss this
> construct !


Well, it's available as a GCC extension [1] at the least.
Consider, e. g.:

$ cat < g4u68ss8m8usbkqkx33wtfwws8.c
/*** g4u68ss8m8usbkqkx33wtfwws8.c -*- C -*- */

#include <stdio.h> /* for printf () */

int
main ()
{
int a = ({
int x = 21, y;
if (1) {
y = 2 * x;
} else {
y = 13;
}
/* . */
y;
});

printf ("a = %d\n", a);

/* . */
return 0;
}

/*** g4u68ss8m8usbkqkx33wtfwws8.c ends here */
$ make g4u68ss8m8usbkqkx33wtfwws8
cc g4u68ss8m8usbkqkx33wtfwws8.c -o g4u68ss8m8usbkqkx33wtfwws8
$ ./g4u68ss8m8usbkqkx33wtfwws8
a = 42
$

[1] http://gcc.gnu.org/onlinedocs/gcc-4....ent-Exprs.html

> Though I don't miss the Lvalue/Rvalue persnickity business (though
> BCPL wasn't as silly as BLISS).


> Thanks for the memories,


--
FSF associate member #7257

Ivan Shmakov 11-28-2012 06:37 AM

Re: Getting started with AVR and C
 
>>>>> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>>>>> Ivan Shmakov <oneingray@gmail.com> writes:


[...]

>> Note that whenever all the operands are integer, an integer
>> operation is performed. (So, 7 / 3 is 2.) The result is as wide as
>> the widest of the operands. (So, i + j is 0 if i is 255, j is 1,
>> and both are declared to be of the 8-bit unsigned integer uint8_t
>> type.)


> No, the return will be of type int in that case. The rules are
> rather involved, but the gist of it is that everything "smaller" than
> an int gets converted to an int. When the types involved are int or
> larger, both get converted to the larger type.


Thus:

Generally, the result is as wide as the widest of the operands, or
"int", if no operand is wider than "int". The result then may be
truncated on function application or assignment. (For instance,
i += j is 0 if i is 1, j is 255, and both are declared to be of the
8-bit unsigned integer uint8_t type.)

> Mixed signed and unsigned types generally result in the signed
> operand being converted to the type of the unsigned operand (after
> promotion).


> The standard takes pages to describe these rules, so there is no way
> I can summarise them here with 100% accuracy. Given that you summary
> is not short, it might be worth including them. You'd then need to
> say to which operators they apply (for example they don't apply to
> the shift operators).


Perhaps. Though this seems to open yet another can of worms.

[...]

>> * a the value of the memory cell at address
>> a


> This rather reinforces a view of C are lower-level than it really is.
> The result might not square with how people think of a memory cell
> (for example, if a is a function pointer, or when it is pointer to a
> struct type).


Yes, but nowhere in the summary I talk about struct's (even
should they be regarded as one of the essential conveniences of
the language), and function pointers seem far too advanced a
concept for those just starting to use C. And yes, pointers in
C are typed, which made me hesitate to mention them at all in
this summary.

>> & a the address of a (must be an "l-value")
>> ~ a bitwise negated a
>> ! a 1 if a is 0,
>> 0 otherwise


> You don't talk about array the indexing operator, [], not the
> function call operator, (). there are others, too, like sizeof and
> cast operators.


... And also . and ->. But then, I've omitted both arrays and
structs altogether, and show function calls and variable
declarations only on examples.

> In tabular summary, I don't think it hurts to be complete.


Frankly, I've tried to focus on "consistency", not completeness.
That is, this summary was intended to provide an example of
"basic", "self-contained" C programming, even if unsuitable for
the majority of practical tasks.

[...]

>> a << b a times 2 ^b (shift left)
>> a >> b a times 2 ^(-b) (shift right)


> These ones are tricky because of all the corner cases (a shift equal
> or greater than the operand size, a shift of a bit into the sign
> position,


Shouldn't these issues be already familiar to those coming from
the embedded programming background?

> a right shift of a negative quantity).


Seems like an interesting case, indeed. (I fail to recall if I
ever needed to do that.)

> In a summary like this may just a footnote to "beware".


ACK, thanks.

[...]

>> Operations with side-effects


>> NB: a must be an "l-value"


> Yes and it might help to say which of the expression yield and
> lvalue. For example, you can write ++*a but not ++!a. It's might
> well be obvious, but you could have a column for "is an lvalue".


Indeed, thanks.

[...]

>> a += b a + b a set to value
>> a -= b a - b a set to value
>> a *= b a b a set to value
>> a /= b a / b a set to value


> a %= b is missing.


Indeed. Seems like quite a rarely used operator, though.

> But maybe it's better to generalise: a op= b and say what op can be?


It may have its merits, but as long as simple text search is
considered, it makes sense to mention the exact form of all the
operators. (Even if they share the description.)

[...]

>> Naturally, both "=" and "," can be "nested", thus:


> In most tables of operators, you see both priority and associativity.
> Assign ment does not yield an lvalue, so a = b = 0 only works because
> = associates to the right a = (b = 0). Most C binary operators
> associate to the left (i. e. a - b - c means (a - b) - c).


> You could make a really rich summary table that shows priority,
> associativity, whether the expression denotes an lvalue and what
> happens to the operands (are they just promoted as for the shift
> operands or are the "usual arithmetic conversions" applied as for +
> and *). I can see why you would want to avoid too much detail in a
> simple explanation like this, but it does seem like a useful thing to
> do.


Well, it seems like there already is such a table at [1].

My point is that, more often than not, one doesn't bother about
precedence: the arithmetics follows the usual rules (a + b * c =
a + (b * c)), and when the other operators are involved, it does
no harm to parenthesize the subexpressions to make the order
explicit.

[1] http://en.wikibooks.org/wiki/C_Progr...e_of_Operators

>> for (a = b = 0, c = 5; c > 0; a++, b++, c--) {
>> /* ... */
>> }


>> To note is that the for () <statement> form is just a short-hand for
>> a specific while () loop. For instance, the for () statement above
>> can be rewritten as follows:


>> a = b = 0, c = 5;
>> while (c > 0) {
>> /* ... */
>> a++, b++, c--;
>> }


> Provided that /* ... */ contains no continue statements (except as
> part of a nested statement of course).


Indeed, I've missed this case. Thanks!

[...]

>> A similar idiom is possible for the ?:-operator just as well.
>> Consider, e. g.:


>> a = (b ? c
>> : d ? e
>> : f);


>> which is not dissimilar to more verbose (and error-prone):


>> if (b) {
>> a = c;
>> } else if (d) {
>> a = e;
>> } else {
>> a = f;
>> }


> You will find disagreement about that parenthetical remark in
> comp.lang.c.


My point here is that when one (for whatever reason) has to
rename "a", it's easier to forget to update all the "if"
branches in the former example than the single reference in the
latter.

The same logic dictates the preference for a += b; over more
"Fortran-friendly" a = a + b;.

--
FSF associate member #7257

Ben Bacarisse 11-28-2012 02:49 PM

Re: Getting started with AVR and C
 
Ivan Shmakov <oneingray@gmail.com> writes:

>>>>>> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>>>>>> Ivan Shmakov <oneingray@gmail.com> writes:

<snip>
> >> a << b a times 2 ^b (shift left)
> >> a >> b a times 2 ^(-b) (shift right)

>
> > These ones are tricky because of all the corner cases (a shift equal
> > or greater than the operand size, a shift of a bit into the sign
> > position,

>
> Shouldn't these issues be already familiar to those coming from
> the embedded programming background?


The trouble is that people often think that what happened on the CPUs
they've used before is what will happen on the next one. In other words
there's a tendency to extrapolate form "what happens" to "what is
defined to happen". But maybe the world of embedded programming is so
diverse that people rarely make these assumptions.

<snip>
> > You could make a really rich summary table that shows priority,
> > associativity, whether the expression denotes an lvalue and what
> > happens to the operands (are they just promoted as for the shift
> > operands or are the "usual arithmetic conversions" applied as for +
> > and *). I can see why you would want to avoid too much detail in a
> > simple explanation like this, but it does seem like a useful thing to
> > do.

>
> Well, it seems like there already is such a table at [1].


Well I meant something more than that, but I understand your desire to
keep things simple.

The interesting things about C operators are the result type and value,
the conversions that are done to the operands (simple promotion or "the
usual arithmetic conversions"), the precedence and associativity,
whether the result denotes an lvalue, and any side effects. Maybe
that's too much for a single table, but I might have a go though.

<snip>
--
Ben.

Frank Miles 11-28-2012 05:53 PM

Re: Getting started with AVR and C
 

> Generally, the result is as wide as the widest of the operands, or
> "int", if no operand is wider than "int". The result then may be
> truncated on function application or assignment. (For instance, i
> += j is 0 if i is 1, j is 255, and both are declared to be of the
> 8-bit unsigned integer uint8_t type.)
>


And you have to be careful about how/when any expansions occur. For
example with gcc-avr, if you want

int32_t = int16_t * int16_t

(the full 32 bit result of a 16x16 bit multiply), you have to cast each
of the 16-bit operands to 32bits.

Grant Edwards 11-28-2012 06:05 PM

Re: Getting started with AVR and C
 
On 2012-11-28, Frank Miles <fpm@u.washington.edu> wrote:
>
>> Generally, the result is as wide as the widest of the operands, or
>> "int", if no operand is wider than "int". The result then may be
>> truncated on function application or assignment. (For instance, i
>> += j is 0 if i is 1, j is 255, and both are declared to be of the
>> 8-bit unsigned integer uint8_t type.)
>>

>
> And you have to be careful about how/when any expansions occur. For
> example with gcc-avr, if you want
>
> int32_t = int16_t * int16_t
>
> (the full 32 bit result of a 16x16 bit multiply), you have to cast each
> of the 16-bit operands to 32bits.


Shouldn't casting just one of the 16 bit values work the same as
casting both of them?

--
Grant Edwards grant.b.edwards Yow! It's NO USE ... I've
at gone to "CLUB MED"!!
gmail.com


All times are GMT. The time now is 08:19 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.