Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #28629 > unrolled thread

Re: Getting started with AVR and C

Started byIvan Shmakov <oneingray@gmail.com>
First post2012-11-25 04:18 +0700
Last post2012-11-27 10:21 +0100
Articles 20 on this page of 87 — 26 participants

Back to article view | Back to comp.lang.c

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Getting started with AVR and C Ivan Shmakov <oneingray@gmail.com> - 2012-11-25 04:18 +0700
    Re: Getting started with AVR and C Richard Damon <news.x.richarddamon@xoxy.net> - 2012-11-24 17:09 -0500
    Re: Getting started with AVR and C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-11-24 22:12 +0000
      statement / expression contexts in C Ivan Shmakov <oneingray@gmail.com> - 2012-11-28 12:54 +0700
      Re: Getting started with AVR and C Ivan Shmakov <oneingray@gmail.com> - 2012-11-28 13:37 +0700
        Re: Getting started with AVR and C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-11-28 14:49 +0000
        Re: Getting started with AVR and C Frank Miles <fpm@u.washington.edu> - 2012-11-28 17:53 +0000
          Re: Getting started with AVR and C Grant Edwards <invalid@invalid.invalid> - 2012-11-28 18:05 +0000
            Re: Getting started with AVR and C Tim Wescott <tim@seemywebsite.com> - 2012-11-28 12:56 -0600
              Re: Getting started with AVR and C glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-11-28 21:45 +0000
                Re: Getting started with AVR and C Tim Wescott <tim@seemywebsite.com> - 2012-11-28 15:55 -0600
                Re: Getting started with AVR and C David Brown <david.brown@removethis.hesbynett.no> - 2012-11-29 01:35 +0100
                  Re: Getting started with AVR and C Hans-Bernhard Bröker <HBBroeker@t-online.de> - 2012-11-29 01:47 +0100
                    Re: Getting started with AVR and C David Brown <david@westcontrol.removethisbit.com> - 2012-11-29 09:24 +0100
                  Re: Getting started with AVR and C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-11-29 01:18 +0000
                    Re: Getting started with AVR and C Tim Wescott <tim@seemywebsite.com> - 2012-11-28 20:07 -0600
                      Re: Getting started with AVR and C Grant Edwards <invalid@invalid.invalid> - 2012-11-29 15:23 +0000
                        Re: Getting started with AVR and C James Kuyper <jameskuyper@verizon.net> - 2012-11-29 11:01 -0500
                          Re: Getting started with AVR and C Grant Edwards <invalid@invalid.invalid> - 2012-11-29 19:19 +0000
                            Re: Getting started with AVR and C James Kuyper <jameskuyper@verizon.net> - 2012-11-29 14:32 -0500
                          Re: Getting started with AVR and C Jon Kirwan <jonk@infinitefactors.org> - 2012-11-29 11:44 -0800
                            Re: Getting started with AVR and C glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-11-29 21:23 +0000
                              Re: Getting started with AVR and C Keith Thompson <kst-u@mib.org> - 2012-11-29 18:15 -0800
                          Re: Getting started with AVR and C upsidedown@downunder.com - 2012-11-29 22:17 +0200
                            Re: Getting started with AVR and C Keith Thompson <kst-u@mib.org> - 2012-11-29 12:36 -0800
                              Re: Getting started with AVR and C Stephen Sprunk <stephen@sprunk.org> - 2012-11-29 16:22 -0600
                                Re: Getting started with AVR and C Keith Thompson <kst-u@mib.org> - 2012-11-29 18:36 -0800
                              Re: Getting started with AVR and C "Boudewijn Dijkstra" <sp4mtr4p.boudewijn@indes.com> - 2012-12-11 10:53 +0100
                                Re: Getting started with AVR and C John Devereux <john@devereux.me.uk> - 2012-12-11 14:53 +0000
                                  Unicode Ivan Shmakov <oneingray@gmail.com> - 2012-12-14 23:25 +0700
                                  Re: Getting started with AVR and C Richard Damon <news.x.richarddamon@xoxy.net> - 2012-12-15 14:30 -0500
                                    Re: Getting started with AVR and C Keith Thompson <kst-u@mib.org> - 2012-12-15 12:24 -0800
                                      Re: Getting started with AVR and C Richard Damon <news.x.richarddamon@xoxy.net> - 2012-12-15 18:02 -0500
                                        Re: Getting started with AVR and C Keith Thompson <kst-u@mib.org> - 2012-12-15 15:45 -0800
                                          Re: Getting started with AVR and C Richard Damon <news.x.richarddamon@xoxy.net> - 2012-12-16 22:55 -0500
                                            Re: Getting started with AVR and C Keith Thompson <kst-u@mib.org> - 2012-12-16 23:20 -0800
                                        Re: Getting started with AVR and C Phil Carmody <thefatphil_demunged@yahoo.co.uk> - 2012-12-17 12:27 +0200
                                      Re: Getting started with AVR and C John Devereux <john@devereux.me.uk> - 2012-12-17 11:17 +0000
                                        Re: Getting started with AVR and C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-12-17 14:07 +0000
                                    Re: Getting started with AVR and C Nobody <nobody@nowhere.com> - 2012-12-16 03:28 +0000
                                    Re: Getting started with AVR and C upsidedown@downunder.com - 2012-12-16 10:40 +0200
                  Re: Getting started with AVR and C glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-11-29 02:31 +0000
                    Re: Getting started with AVR and C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-11-29 03:36 +0000
                      Re: Getting started with AVR and C glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-11-29 03:55 +0000
                    Re: Getting started with AVR and C David Brown <david@westcontrol.removethisbit.com> - 2012-11-29 09:37 +0100
                      Re: Getting started with AVR and C glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-11-29 11:31 +0000
                        Re: Getting started with AVR and C David Brown <david@westcontrol.removethisbit.com> - 2012-11-29 13:44 +0100
                      Re: Getting started with AVR and C Hans-Bernhard Bröker <HBBroeker@t-online.de> - 2012-11-29 13:22 +0100
                        Re: Getting started with AVR and C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-11-29 13:32 +0000
                          Re: Getting started with AVR and C Keith Thompson <kst-u@mib.org> - 2012-11-29 11:28 -0800
                      Re: Getting started with AVR and C Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-11-29 13:20 +0000
                      Re: Getting started with AVR and C James Kuyper <jameskuyper@verizon.net> - 2012-11-29 09:07 -0500
                        Re: Getting started with AVR and C James Kuyper <jameskuyper@verizon.net> - 2012-11-29 09:17 -0500
                          Re: Getting started with AVR and C pete <pfiland@mindspring.com> - 2012-11-29 18:25 -0500
                            Re: Getting started with AVR and C James Kuyper <jameskuyper@verizon.net> - 2012-11-29 22:46 -0500
                              Re: Getting started with AVR and C lawrence.jones@siemens.com - 2012-11-30 11:47 -0500
                            Re: Getting started with AVR and C Tim Rentsch <txr@alumni.caltech.edu> - 2012-12-17 03:53 -0800
                        Re: Getting started with AVR and C Keith Thompson <kst-u@mib.org> - 2012-11-29 11:38 -0800
                          Re: Getting started with AVR and C James Kuyper <jameskuyper@verizon.net> - 2012-11-29 15:21 -0500
              Re: Getting started with AVR and C Grant Edwards <invalid@invalid.invalid> - 2012-11-28 22:26 +0000
                Re: Getting started with AVR and C Tim Wescott <tim@seemywebsite.com> - 2012-11-28 17:32 -0600
                  Re: Getting started with AVR and C James Kuyper <jameskuyper@verizon.net> - 2012-11-28 19:02 -0500
                    Re: Getting started with AVR and C Tim Wescott <tim@seemywebsite.com> - 2012-11-28 18:29 -0600
                      Re: Getting started with AVR and C James Kuyper <jameskuyper@verizon.net> - 2012-11-28 23:39 -0500
                        Re: Getting started with AVR and C Tim Wescott <tim@seemywebsite.please> - 2012-11-29 00:59 -0600
                          Re: Getting started with AVR and C James Kuyper <jameskuyper@verizon.net> - 2012-11-29 07:57 -0500
                            Re: Getting started with AVR and C Tim Wescott <tim@seemywebsite.com> - 2012-11-29 13:02 -0600
                          Re: Getting started with AVR and C Grant Edwards <invalid@invalid.invalid> - 2012-11-29 15:19 +0000
                        Re: Getting started with AVR and C Phil Carmody <thefatphil_demunged@yahoo.co.uk> - 2012-11-29 12:03 +0200
                          Re: Getting started with AVR and C glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2012-11-29 11:39 +0000
                          Re: Getting started with AVR and C James Kuyper <jameskuyper@verizon.net> - 2012-11-29 08:04 -0500
                      Re: Getting started with AVR and C Grant Edwards <invalid@invalid.invalid> - 2012-11-29 15:17 +0000
              Re: Getting started with AVR and C Tim Wescott <tim@seemywebsite.com> - 2012-11-28 19:19 -0600
                Re: Getting started with AVR and C James Kuyper <jameskuyper@verizon.net> - 2012-11-28 23:44 -0500
          Re: Getting started with AVR and C James Kuyper <jameskuyper@verizon.net> - 2012-11-28 13:15 -0500
            Re: Getting started with AVR and C Arlet Ottens <usenet+5@c-scape.nl> - 2012-11-28 19:17 +0100
              Re: Getting started with AVR and C Tim Wescott <tim@seemywebsite.com> - 2012-11-28 19:30 -0600
                Re: Getting started with AVR and C Grant Edwards <invalid@invalid.invalid> - 2012-11-29 15:29 +0000
                  Re: Getting started with AVR and C John Devereux <john@devereux.me.uk> - 2012-11-29 16:36 +0000
                    Re: Getting started with AVR and C upsidedown@downunder.com - 2012-11-29 22:40 +0200
                      Re: Getting started with AVR and C Jon Kirwan <jonk@infinitefactors.org> - 2012-11-29 13:55 -0800
                        Re: Getting started with AVR and C Grant Edwards <invalid@invalid.invalid> - 2012-11-29 22:06 +0000
                          Re: Getting started with AVR and C Jon Kirwan <jonk@infinitefactors.org> - 2012-11-29 14:22 -0800
                      Re: Getting started with AVR and C Grant Edwards <invalid@invalid.invalid> - 2012-11-29 21:59 +0000
                        Re: Getting started with AVR and C John Devereux <john@devereux.me.uk> - 2012-11-30 08:29 +0000
    Re: Getting started with AVR and C Nick Keighley <nick_keighley_nospam@hotmail.com> - 2012-11-25 05:41 -0800
    Re: Getting started with AVR and C Rosario1903 <Rosario@invalid.invalid> - 2012-11-27 10:21 +0100

Page 1 of 5  [1] 2 3 4 5  Next page →


#28629 — Re: Getting started with AVR and C

FromIvan Shmakov <oneingray@gmail.com>
Date2012-11-25 04:18 +0700
SubjectRe: Getting started with AVR and C
Message-ID<86boem66on.fsf@gray.siamics.net>
>>>>> 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

[toc] | [next] | [standalone]


#28630

FromRichard Damon <news.x.richarddamon@xoxy.net>
Date2012-11-24 17:09 -0500
Message-ID<k8rgi8$phk$1@dont-email.me>
In reply to#28629
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).

[toc] | [prev] | [next] | [standalone]


#28631

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-11-24 22:12 +0000
Message-ID<0.4196fd606ae8a0c4ce3e.20121124221204GMT.87zk26y7kb.fsf@bsb.me.uk>
In reply to#28629
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.

[toc] | [prev] | [next] | [standalone]


#28719 — statement / expression contexts in C

FromIvan Shmakov <oneingray@gmail.com>
Date2012-11-28 12:54 +0700
Subjectstatement / expression contexts in C
Message-ID<86txsa1dcq.fsf_-_@gray.siamics.net>
In reply to#28631
>>>>> 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.7.2/gcc/Statement-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

[toc] | [prev] | [next] | [standalone]


#28722

FromIvan Shmakov <oneingray@gmail.com>
Date2012-11-28 13:37 +0700
Message-ID<86pq2y1bcy.fsf@gray.siamics.net>
In reply to#28631
>>>>> 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_Programming/Reference_Tables#Table_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

[toc] | [prev] | [next] | [standalone]


#28734

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-11-28 14:49 +0000
Message-ID<0.96c7977b73f1cb3bf4d0.20121128144941GMT.87ip8pu6ii.fsf@bsb.me.uk>
In reply to#28722
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.

[toc] | [prev] | [next] | [standalone]


#28735

FromFrank Miles <fpm@u.washington.edu>
Date2012-11-28 17:53 +0000
Message-ID<k95j21$otc$1@dont-email.me>
In reply to#28722
>     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.

[toc] | [prev] | [next] | [standalone]


#28736

FromGrant Edwards <invalid@invalid.invalid>
Date2012-11-28 18:05 +0000
Message-ID<k95joi$qcq$1@reader1.panix.com>
In reply to#28735
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            

[toc] | [prev] | [next] | [standalone]


#28741

FromTim Wescott <tim@seemywebsite.com>
Date2012-11-28 12:56 -0600
Message-ID<JaGdnWuCkdH4wyvNnZ2dnUVZ_oOdnZ2d@web-ster.com>
In reply to#28736
On Wed, 28 Nov 2012 18:05:06 +0000, Grant Edwards wrote:

> 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?

Yes.  But that's if you take "should" as indicating a moral direction, 
rather than as an indication of what you can reasonably expect from every 
tool chain.

I would expect that gcc would be ANSI compliant, and would therefore 
promote both 16-bit integers to 32-bit before doing the multiply.  But 
I've worked with compilers in the past that didn't do this, so when 
writing code that may be used in multiple places, I up-cast the same way 
one votes in Chicago: early and often.

-- 
My liberal friends think I'm a conservative kook.
My conservative friends think I'm a liberal kook.
Why am I not happy that they have found common ground?

Tim Wescott, Communications, Control, Circuits & Software
http://www.wescottdesign.com

[toc] | [prev] | [next] | [standalone]


#28753

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2012-11-28 21:45 +0000
Message-ID<k960mf$ghq$1@speranza.aioe.org>
In reply to#28741
In comp.lang.c Tim Wescott <tim@seemywebsite.com> wrote:
> On Wed, 28 Nov 2012 18:05:06 +0000, Grant Edwards wrote:
 
>> On 2012-11-28, Frank Miles <fpm@u.washington.edu> wrote:

>>> 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?
 
> Yes.  But that's if you take "should" as indicating a moral direction, 
> rather than as an indication of what you can reasonably expect from every 
> tool chain.
 
> I would expect that gcc would be ANSI compliant, and would therefore 
> promote both 16-bit integers to 32-bit before doing the multiply.  

Maybe I am missing something here, but are there versions of gcc for 16
bit processors, with 16 bit int? If so, then promotion to int won't
promote to 32 bits without a cast. 

-- glen

[toc] | [prev] | [next] | [standalone]


#28755

FromTim Wescott <tim@seemywebsite.com>
Date2012-11-28 15:55 -0600
Message-ID<JaGdnWWCkdHAFSvNnZ2dnUVZ_oOdnZ2d@web-ster.com>
In reply to#28753
On Wed, 28 Nov 2012 21:45:51 +0000, glen herrmannsfeldt wrote:

> In comp.lang.c Tim Wescott <tim@seemywebsite.com> wrote:
>> On Wed, 28 Nov 2012 18:05:06 +0000, Grant Edwards wrote:
>  
>>> On 2012-11-28, Frank Miles <fpm@u.washington.edu> wrote:
> 
>>>> 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?
>  
>> Yes.  But that's if you take "should" as indicating a moral direction,
>> rather than as an indication of what you can reasonably expect from
>> every tool chain.
>  
>> I would expect that gcc would be ANSI compliant, and would therefore
>> promote both 16-bit integers to 32-bit before doing the multiply.
> 
> Maybe I am missing something here, but are there versions of gcc for 16
> bit processors, with 16 bit int? If so, then promotion to int won't
> promote to 32 bits without a cast.
> 
> -- glen

Yes.  But a compliant processor will take

int16_t a, b;
int32_t c

c = (int32_t)a * b;

and cast both a and b to 32-bit.

I have worked with compilers that would _demote_ a 32-bit to a 16 bit and 
do the math, unless _both_ operands were cast to 32-bit, i.e.

c = (int32_t)a * (int32_t)b;

Wrong?  Yes.  But if that's what the compiler do, that's what you work 
with...

-- 
My liberal friends think I'm a conservative kook.
My conservative friends think I'm a liberal kook.
Why am I not happy that they have found common ground?

Tim Wescott, Communications, Control, Circuits & Software
http://www.wescottdesign.com

[toc] | [prev] | [next] | [standalone]


#28762

FromDavid Brown <david.brown@removethis.hesbynett.no>
Date2012-11-29 01:35 +0100
Message-ID<TN6dnaDoIqIhMCvNnZ2dnUVZ8v-dnZ2d@lyse.net>
In reply to#28753
On 28/11/12 22:45, glen herrmannsfeldt wrote:
> In comp.lang.c Tim Wescott <tim@seemywebsite.com> wrote:
>> On Wed, 28 Nov 2012 18:05:06 +0000, Grant Edwards wrote:
>
>>> On 2012-11-28, Frank Miles <fpm@u.washington.edu> wrote:
>
>>>> 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?
>
>> Yes.  But that's if you take "should" as indicating a moral direction,
>> rather than as an indication of what you can reasonably expect from every
>> tool chain.
>
>> I would expect that gcc would be ANSI compliant, and would therefore
>> promote both 16-bit integers to 32-bit before doing the multiply.
>
> Maybe I am missing something here, but are there versions of gcc for 16
> bit processors, with 16 bit int? If so, then promotion to int won't
> promote to 32 bits without a cast.
>

The correct behaviour for C standards compliance is that when you 
multiply two operands of different int size, the smaller one is promoted 
to the size of the larger one.  Then the multiply is carried out modulo 
the size of the larger one.  Then the result is truncated or extended as 
needed to fit the target variable.

So the bit-size of the processor, and the bit-size of "int" on that 
particular target, is irrelevant.  And the size of the result variable 
is also irrelevant (this catches out some newbies).

Given:

int16_t a, b;
int32_t c

c = (int32_t)a * b;

Then b is cast to int32_t, the 32-bit multiplication is carried out, and 
the result assigned to c.

If you write just "c = a * b", then the multiplication is carried it at 
16-bit, then promoted to 32-bit.  This applies regardless of the 
bit-size of the target - you will get the same effect on a 64-bit cpu as 
on the 8-bit AVR.


If your compiler does 16-bit multiplications when you have "c = 
(int32_t) a * b", and requires two "int32_t" casts to do 32-bit 
multiplication, then your compiler is very badly broken.  As Tim says, 
badly broken compilers /do/ exist, so if you have to use them, then you 
need to use two casts.  But I personally don't think you need to write 
your code to work with broken toolchains unless you actually have to.


[toc] | [prev] | [next] | [standalone]


#28763

FromHans-Bernhard Bröker <HBBroeker@t-online.de>
Date2012-11-29 01:47 +0100
Message-ID<ahnplnFbufpU1@mid.dfncis.de>
In reply to#28762
On 29.11.2012 01:35, David Brown wrote:

> The correct behaviour for C standards compliance is that when you
> multiply two operands of different int size, the smaller one is promoted
> to the size of the larger one.

Close, but not cigar.  You forgot about types smaller than the 
platform's "int".  Those will be converted up to either signed or 
unsigned int anyway, i.e. even if both operands are of the same size.

> So the bit-size of the processor, and the bit-size of "int" on that
> particular target, is irrelevant.

Incorrect.  It is very relevant as soon as either of the operands' types 
is smaller than "int" on the particular target.

The rule to remember is that C never does arithmetic on anything smaller 
than an 'int'.

> Given:
>
> int16_t a, b;
> int32_t c
>
> If you write just "c = a * b", then the multiplication is carried it at
> 16-bit, then promoted to 32-bit.

Not if you're on a 32-bit target it isn't.  Default conversion to 32-bit 
int takes place first, so both operands are first converted to 32-bit, 
then a 32 x 32 --> 32 bit multiply is carried out.  At least in 
principle (that is: modulo the "as-if rule").

[toc] | [prev] | [next] | [standalone]


#28778

FromDavid Brown <david@westcontrol.removethisbit.com>
Date2012-11-29 09:24 +0100
Message-ID<xJmdne4-9L7HgCrNnZ2dnUVZ8s-dnZ2d@lyse.net>
In reply to#28763
On 29/11/2012 01:47, Hans-Bernhard Bröker wrote:
> On 29.11.2012 01:35, David Brown wrote:
>
>> The correct behaviour for C standards compliance is that when you
>> multiply two operands of different int size, the smaller one is promoted
>> to the size of the larger one.
>
> Close, but not cigar.  You forgot about types smaller than the
> platform's "int".  Those will be converted up to either signed or
> unsigned int anyway, i.e. even if both operands are of the same size.
>
>> So the bit-size of the processor, and the bit-size of "int" on that
>> particular target, is irrelevant.
>
> Incorrect.  It is very relevant as soon as either of the operands' types
> is smaller than "int" on the particular target.
>
> The rule to remember is that C never does arithmetic on anything smaller
> than an 'int'.
>
>> Given:
>>
>> int16_t a, b;
>> int32_t c
>>
>> If you write just "c = a * b", then the multiplication is carried it at
>> 16-bit, then promoted to 32-bit.
>
> Not if you're on a 32-bit target it isn't.  Default conversion to 32-bit
> int takes place first, so both operands are first converted to 32-bit,
> then a 32 x 32 --> 32 bit multiply is carried out.  At least in
> principle (that is: modulo the "as-if rule").

Of course you are correct here.  I should not be posting so late - or I 
should have drunk more coffee first, because I know this stuff (as long 
as my brain is functioning correctly!).

Apologies if I've added to the confusion here, and thanks for the 
correction.

[toc] | [prev] | [next] | [standalone]


#28764

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-11-29 01:18 +0000
Message-ID<0.b3ca9d18d0528a0b5ff8.20121129011842GMT.871ufdtde5.fsf@bsb.me.uk>
In reply to#28762
David Brown <david.brown@removethis.hesbynett.no> writes:
<snip>
> The correct behaviour for C standards compliance is that when you
> multiply two operands of different int size, the smaller one is
> promoted to the size of the larger one.

Not exactly, no, though there is some confusion because you talk of
different int sizes.  int is one C type so there is only one int size,
but I'm assuming you meant "integer types of different size".

If that's what you meant, it's not quite right because multiplying a
short by a char (for example) will involve promoting both operands to
int.  Other more outlandish examples include multiplying a char by a
_Bool and many cases involving bit fields.

>  Then the multiply is carried
> out modulo the size of the larger one.

That's one commonly observed behaviour but it is not "the correct
behaviour".  If the common type arrived at by the arithmetic conversions
is a signed type, the multiplication may overflow and anything at all
can happen (i.e. what happens is undefined by the C standard).  Unsigned
integer arithmetic does not overflow.

>  Then the result is truncated
> or extended as needed to fit the target variable.

Again, not quite.  The result is converted to type of the object it is
being assigned to, and a great deal of leeway is given to
implementations when the target type is a signed int. If the result
can't be represented in the target type, either the result is
implementation defined or an implementation defined signal is raised.

For unsigned types, the behaviour is entirely defined by the C standard
(conversion modulo 2^width which is, as you say, truncation).

> So the bit-size of the processor, and the bit-size of "int" on that
> particular target, is irrelevant.  And the size of the result variable
> is also irrelevant (this catches out some newbies).
>
> Given:
>
> int16_t a, b;
> int32_t c
>
> c = (int32_t)a * b;
>
> Then b is cast to int32_t, the 32-bit multiplication is carried out,
> and the result assigned to c.

(unless int happens to be wider than 32 bits)

> If you write just "c = a * b", then the multiplication is carried it
> at 16-bit, then promoted to 32-bit.  This applies regardless of the
> bit-size of the target - you will get the same effect on a 64-bit cpu
> as on the 8-bit AVR.

The machine bit-size is not really the thing that matters.  What matters
is the sizes assigned to the various types by the C implementation.
What you say is roughly correct for an implementation with a 16 bit int
type ("roughly" because of the possibility of overflow).

The size given to int is often the natural one (or one of the natural
ones) for the machine in question.  When this is the case, the bit size
of the target does matter, but only because of the differing int sizes.

> If your compiler does 16-bit multiplications when you have "c =
> (int32_t) a * b", and requires two "int32_t" casts to do 32-bit
> multiplication, then your compiler is very badly broken.  As Tim says,
> badly broken compilers /do/ exist, so if you have to use them, then
> you need to use two casts.  But I personally don't think you need to
> write your code to work with broken toolchains unless you actually
> have to.

It leads to a special kind of hell!  When you can't ever shake off the
idea that x, y or z once went wrong on compiler p, q or r, you end up
having to fold every trick you ever used to get your code past bad
compilers into every program.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#28767

FromTim Wescott <tim@seemywebsite.com>
Date2012-11-28 20:07 -0600
Message-ID<JaGdnZ29kdH_XivNnZ2dnUVZ_oOdnZ2d@web-ster.com>
In reply to#28764
On Thu, 29 Nov 2012 01:18:42 +0000, Ben Bacarisse wrote:

> David Brown <david.brown@removethis.hesbynett.no> writes: <snip>
>> The correct behaviour for C standards compliance is that when you
>> multiply two operands of different int size, the smaller one is
>> promoted to the size of the larger one.
> 
> Not exactly, no, though there is some confusion because you talk of
> different int sizes.  int is one C type so there is only one int size,
> but I'm assuming you meant "integer types of different size".
> 
> If that's what you meant, it's not quite right because multiplying a
> short by a char (for example) will involve promoting both operands to
> int.  Other more outlandish examples include multiplying a char by a
> _Bool and many cases involving bit fields.
> 
>>  Then the multiply is carried
>> out modulo the size of the larger one.
> 
> That's one commonly observed behaviour but it is not "the correct
> behaviour".  If the common type arrived at by the arithmetic conversions
> is a signed type, the multiplication may overflow and anything at all
> can happen (i.e. what happens is undefined by the C standard).  Unsigned
> integer arithmetic does not overflow.
> 
>>  Then the result is truncated
>> or extended as needed to fit the target variable.
> 
> Again, not quite.  The result is converted to type of the object it is
> being assigned to, and a great deal of leeway is given to
> implementations when the target type is a signed int. If the result
> can't be represented in the target type, either the result is
> implementation defined or an implementation defined signal is raised.
> 
> For unsigned types, the behaviour is entirely defined by the C standard
> (conversion modulo 2^width which is, as you say, truncation).
> 
>> So the bit-size of the processor, and the bit-size of "int" on that
>> particular target, is irrelevant.  And the size of the result variable
>> is also irrelevant (this catches out some newbies).
>>
>> Given:
>>
>> int16_t a, b;
>> int32_t c
>>
>> c = (int32_t)a * b;
>>
>> Then b is cast to int32_t, the 32-bit multiplication is carried out,
>> and the result assigned to c.
> 
> (unless int happens to be wider than 32 bits)
> 
>> If you write just "c = a * b", then the multiplication is carried it at
>> 16-bit, then promoted to 32-bit.  This applies regardless of the
>> bit-size of the target - you will get the same effect on a 64-bit cpu
>> as on the 8-bit AVR.
> 
> The machine bit-size is not really the thing that matters.  What matters
> is the sizes assigned to the various types by the C implementation. What
> you say is roughly correct for an implementation with a 16 bit int type
> ("roughly" because of the possibility of overflow).
> 
> The size given to int is often the natural one (or one of the natural
> ones) for the machine in question.  When this is the case, the bit size
> of the target does matter, but only because of the differing int sizes.
> 
>> If your compiler does 16-bit multiplications when you have "c =
>> (int32_t) a * b", and requires two "int32_t" casts to do 32-bit
>> multiplication, then your compiler is very badly broken.  As Tim says,
>> badly broken compilers /do/ exist, so if you have to use them, then you
>> need to use two casts.  But I personally don't think you need to write
>> your code to work with broken toolchains unless you actually have to.
> 
> It leads to a special kind of hell!  When you can't ever shake off the
> idea that x, y or z once went wrong on compiler p, q or r, you end up
> having to fold every trick you ever used to get your code past bad
> compilers into every program.

Me, I just try to remember that x, y or z went wrong on some compiler 
some time, so that if I see symptoms again those problems are on my short 
list, and maybe even a fix or two.

Like Texas Instrument's Code Composter for the TMS320F2812, which has a 
32-bit "double".  #$%@.

-- 
My liberal friends think I'm a conservative kook.
My conservative friends think I'm a liberal kook.
Why am I not happy that they have found common ground?

Tim Wescott, Communications, Control, Circuits & Software
http://www.wescottdesign.com

[toc] | [prev] | [next] | [standalone]


#28801

FromGrant Edwards <invalid@invalid.invalid>
Date2012-11-29 15:23 +0000
Message-ID<k97ulf$jpg$3@reader1.panix.com>
In reply to#28767
On 2012-11-29, Tim Wescott <tim@seemywebsite.com> wrote:
> On Thu, 29 Nov 2012 01:18:42 +0000, Ben Bacarisse wrote:

> Me, I just try to remember that x, y or z went wrong on some compiler 
> some time, so that if I see symptoms again those problems are on my short 
> list, and maybe even a fix or two.
>
> Like Texas Instrument's Code Composter for the TMS320F2812, which has a 
> 32-bit "double".  #$%@.

Or on the TMS320C40, where char, int, long, long long, float and
double are all 32 bits and all have a sizeof() 1.  Trying to impliment
any sort of communications protocol with that was fun.

-- 
Grant Edwards               grant.b.edwards        Yow! Is it NOUVELLE
                                  at               CUISINE when 3 olives are
                              gmail.com            struggling with a scallop
                                                   in a plate of SAUCE MORNAY?

[toc] | [prev] | [next] | [standalone]


#28804

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-11-29 11:01 -0500
Message-ID<k980sv$sh4$1@dont-email.me>
In reply to#28801
On 11/29/2012 10:23 AM, Grant Edwards wrote:
> On 2012-11-29, Tim Wescott <tim@seemywebsite.com> wrote:
>> On Thu, 29 Nov 2012 01:18:42 +0000, Ben Bacarisse wrote:
> 
>> Me, I just try to remember that x, y or z went wrong on some compiler 
>> some time, so that if I see symptoms again those problems are on my short 
>> list, and maybe even a fix or two.
>>
>> Like Texas Instrument's Code Composter for the TMS320F2812, which has a 
>> 32-bit "double".  #$%@.
> 
> Or on the TMS320C40, where char, int, long, long long, float and
> double are all 32 bits and all have a sizeof() 1. ...

There's a key difference there. The implementation you describe could be
fully conforming. The one he described could not; you can't meet the
standard's precision and range requirements for double with a 32-bit
data type.

> ...  Trying to impliment
> any sort of communications protocol with that was fun.

Thanks for that information. Claims have frequently been made on
comp.lang.c that, while the C standard allows CHAR_BIT != 8, the
existence of such implementations is a myth. I'm glad to have a specific
counter example to cite.
There's something I've wondered about such machines: when data from
other machines containing data types smaller than 32 bits (for instance,
ASCII text files) is transferred to the TMS320C40,  how is this usually
handled? I could imagine three main possibilities:

a) Four 8-bit bytes of data are packed into each 32-bit byte
b) Each field value stored in a data type smaller than 32 bits is
converted to a 32-bit type, and stored as such. For instance, a file
containing 45,678 8-bit bytes of text gets converted into a file
containing 45,678 32-bit bytes of text.
c) Different methods are used in different contexts, leading to constant
headaches. This strikes me as the most likely possibility.
-- 
James Kuyper

[toc] | [prev] | [next] | [standalone]


#28814

FromGrant Edwards <invalid@invalid.invalid>
Date2012-11-29 19:19 +0000
Message-ID<k98cfs$lnr$1@reader1.panix.com>
In reply to#28804
On 2012-11-29, James Kuyper <jameskuyper@verizon.net> wrote:
> On 11/29/2012 10:23 AM, Grant Edwards wrote:
>> On 2012-11-29, Tim Wescott <tim@seemywebsite.com> wrote:
>>> On Thu, 29 Nov 2012 01:18:42 +0000, Ben Bacarisse wrote:
>> 
>>> Me, I just try to remember that x, y or z went wrong on some compiler 
>>> some time, so that if I see symptoms again those problems are on my short 
>>> list, and maybe even a fix or two.
>>>
>>> Like Texas Instrument's Code Composter for the TMS320F2812, which has a 
>>> 32-bit "double".  #$%@.
>> 
>> Or on the TMS320C40, where char, int, long, long long, float and
>> double are all 32 bits and all have a sizeof() 1. ...
>
> There's a key difference there. The implementation you describe could
> be fully conforming. The one he described could not; you can't meet
> the standard's precision and range requirements for double with a
> 32-bit data type.

Well, the case I cited had 32-bit doubles. Other than that, I think it
was conforming.  When trying to reuse source modules, it's shocking
how many assumptions I make that aren't implied by the C standard.

>> ...  Trying to impliment any sort of communications protocol with
>> that was fun.
>
> Thanks for that information. Claims have frequently been made on
> comp.lang.c that, while the C standard allows CHAR_BIT != 8, the
> existence of such implementations is a myth. I'm glad to have a
> specific counter example to cite.

If you look at some other DSPs, I think you'll find similar examples
where everything is 16 bits (they tend not to support FP at all).

> There's something I've wondered about such machines: when data from
> other machines containing data types smaller than 32 bits (for
> instance, ASCII text files) is transferred to the TMS320C40, how is
> this usually handled? I could imagine three main possibilities:

A TMS320 is a DSP, and I doubt there are any that have actual
filesystems.  OTOH, high-speed serial interfaces are common, and
filling in things like protocol headers involves a lot of
shifting/masking/anding/oring.

> a) Four 8-bit bytes of data are packed into each 32-bit byte

That's pretty common for data being sent to/from "normal" CPUs.

> b) Each field value stored in a data type smaller than 32 bits is
>    converted to a 32-bit type, and stored as such. For instance, a
>    file containing 45,678 8-bit bytes of text gets converted into a
>    file containing 45,678 32-bit bytes of text.

If you need to do any sort of string manipulation (which you try to
avoid like the plague), that's what you end up doing.

> c) Different methods are used in different contexts, leading to
>    constant headaches. This strikes me as the most likely possibility.

Exactly.

And the icing on the cake is that the 32-bit FP represention isn't
IEEE-784, so you also get to convert between external and internal FP
representations also.  Fun!

-- 
Grant Edwards               grant.b.edwards        Yow! My NOSE is NUMB!
                                  at               
                              gmail.com            

[toc] | [prev] | [next] | [standalone]


#28816

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-11-29 14:32 -0500
Message-ID<k98d8j$gn4$1@dont-email.me>
In reply to#28814
On 11/29/2012 02:19 PM, Grant Edwards wrote:
> On 2012-11-29, James Kuyper <jameskuyper@verizon.net> wrote:
>> On 11/29/2012 10:23 AM, Grant Edwards wrote:
>>> On 2012-11-29, Tim Wescott <tim@seemywebsite.com> wrote:
...
>>>> Like Texas Instrument's Code Composter for the TMS320F2812, which has a 
>>>> 32-bit "double".  #$%@.
>>>
>>> Or on the TMS320C40, where char, int, long, long long, float and
>>> double are all 32 bits and all have a sizeof() 1. ...
>>
>> There's a key difference there. The implementation you describe could
>> be fully conforming. The one he described could not; you can't meet
>> the standard's precision and range requirements for double with a
>> 32-bit data type.
> 
> Well, the case I cited had 32-bit doubles.

Oops - I missed that. OK - a more accurate statement would have been
that  your example had no additional conformance issues that weren't
present in his example.
-- 
James Kuyper

[toc] | [prev] | [next] | [standalone]


Page 1 of 5  [1] 2 3 4 5  Next page →

Back to top | Article view | comp.lang.c


csiph-web