>>>>> 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
Getting started with AVR and C
Started by ●November 24, 2012
Reply by ●November 28, 20122012-11-28
Reply by ●November 28, 20122012-11-28
>>>>> 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
Reply by ●November 28, 20122012-11-28
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.
Reply by ●November 28, 20122012-11-28
> 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.
Reply by ●November 28, 20122012-11-28
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
Reply by ●November 28, 20122012-11-28
On 11/28/2012 12:53 PM, Frank Miles 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.I'm not familiar with gcc-avr. That constitutes a significant deviation from standard C, where casting either operand would be sufficient to guarantee implicit conversion of the other operand, in accordance with the "usual arithmetic conversions". What is the reason for this difference?
Reply by ●November 28, 20122012-11-28
On 11/28/2012 07:15 PM, James Kuyper wrote:> On 11/28/2012 12:53 PM, Frank Miles 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. > > I'm not familiar with gcc-avr. That constitutes a significant deviation > from standard C, where casting either operand would be sufficient to > guarantee implicit conversion of the other operand, in accordance with > the "usual arithmetic conversions". What is the reason for this difference?There's no difference. For gcc-avr it also suffices to cast just one operand.
Reply by ●November 28, 20122012-11-28
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
Reply by ●November 28, 20122012-11-28
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
Reply by ●November 28, 20122012-11-28
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. > > -- glenYes. 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