Arduino / compilers on uC

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View
I've heard the kids here opine compilers are so good
these days that assembly makes no sense.

There's lots to be said for high-level languages. But
I disassembled some Arduino code--here's the output to
write a port pin (a built-in function):


00001006 <digitalWrite>:
    1006:    90 e0           ldi    r25, 0x00    ; 0
    1008:    fc 01           movw    r30, r24
    100a:    e3 52           subi    r30, 0x23    ; 35
    100c:    fd 4f           sbci    r31, 0xFD    ; 253
    100e:    34 91           lpm    r19, Z
    1010:    fc 01           movw    r30, r24
    1012:    e7 53           subi    r30, 0x37    ; 55
    1014:    fd 4f           sbci    r31, 0xFD    ; 253
    1016:    24 91           lpm    r18, Z
    1018:    fc 01           movw    r30, r24
    101a:    eb 54           subi    r30, 0x4B    ; 75
    101c:    fd 4f           sbci    r31, 0xFD    ; 253
    101e:    e4 91           lpm    r30, Z
    1020:    ee 23           and    r30, r30
    1022:    09 f4           brne    .+2          ; 0x1026 <digitalWrite+0x20>
    1024:    3b c0           rjmp    .+118        ; 0x109c <digitalWrite+0x96>
    1026:    33 23           and    r19, r19
    1028:    39 f1           breq    .+78         ; 0x1078 <digitalWrite+0x72>
    102a:    33 30           cpi    r19, 0x03    ; 3
    102c:    91 f0           breq    .+36         ; 0x1052 <digitalWrite+0x4c>
    102e:    38 f4           brcc    .+14         ; 0x103e <digitalWrite+0x38>
    1030:    31 30           cpi    r19, 0x01    ; 1
    1032:    a9 f0           breq    .+42         ; 0x105e <digitalWrite+0x58>
    1034:    32 30           cpi    r19, 0x02    ; 2
    1036:    01 f5           brne    .+64         ; 0x1078 <digitalWrite+0x72>
    1038:    84 b5           in    r24, 0x24    ; 36
    103a:    8f 7d           andi    r24, 0xDF    ; 223
    103c:    12 c0           rjmp    .+36         ; 0x1062 <digitalWrite+0x5c>
    103e:    37 30           cpi    r19, 0x07    ; 7
    1040:    91 f0           breq    .+36         ; 0x1066 <digitalWrite+0x60>
    1042:    38 30           cpi    r19, 0x08    ; 8
    1044:    a1 f0           breq    .+40         ; 0x106e <digitalWrite+0x68>
    1046:    34 30           cpi    r19, 0x04    ; 4
    1048:    b9 f4           brne    .+46         ; 0x1078 <digitalWrite+0x72>
    104a:    80 91 80 00     lds    r24, 0x0080    ; 0x800080 <__data_load_end+0x7fcf9e>
    104e:    8f 7d           andi    r24, 0xDF    ; 223
    1050:    03 c0           rjmp    .+6          ; 0x1058 <digitalWrite+0x52>
    1052:    80 91 80 00     lds    r24, 0x0080    ; 0x800080 <__data_load_end+0x7fcf9e>
    1056:    8f 77           andi    r24, 0x7F    ; 127
    1058:    80 93 80 00     sts    0x0080, r24    ; 0x800080 <__data_load_end+0x7fcf9e>
    105c:    0d c0           rjmp    .+26         ; 0x1078 <digitalWrite+0x72>
    105e:    84 b5           in    r24, 0x24    ; 36
    1060:    8f 77           andi    r24, 0x7F    ; 127
    1062:    84 bd           out    0x24, r24    ; 36
    1064:    09 c0           rjmp    .+18         ; 0x1078 <digitalWrite+0x72>
    1066:    80 91 b0 00     lds    r24, 0x00B0    ; 0x8000b0 <__data_load_end+0x7fcfce>
    106a:    8f 77           andi    r24, 0x7F    ; 127
    106c:    03 c0           rjmp    .+6          ; 0x1074 <digitalWrite+0x6e>
    106e:    80 91 b0 00     lds    r24, 0x00B0    ; 0x8000b0 <__data_load_end+0x7fcfce>
    1072:    8f 7d           andi    r24, 0xDF    ; 223
    1074:    80 93 b0 00     sts    0x00B0, r24    ; 0x8000b0 <__data_load_end+0x7fcfce>
    1078:    f0 e0           ldi    r31, 0x00    ; 0
    107a:    ee 0f           add    r30, r30
    107c:    ff 1f           adc    r31, r31
    107e:    e5 55           subi    r30, 0x55    ; 85
    1080:    fd 4f           sbci    r31, 0xFD    ; 253
    1082:    a5 91           lpm    r26, Z+
    1084:    b4 91           lpm    r27, Z
    1086:    8f b7           in    r24, 0x3f    ; 63
    1088:    f8 94           cli
    108a:    ec 91           ld    r30, X
    108c:    61 11           cpse    r22, r1
    108e:    03 c0           rjmp    .+6          ; 0x1096 <digitalWrite+0x90>
    1090:    20 95           com    r18
    1092:    2e 23           and    r18, r30
    1094:    01 c0           rjmp    .+2          ; 0x1098 <digitalWrite+0x92>
    1096:    2e 2b           or    r18, r30
    1098:    2c 93           st    X, r18
    109a:    8f bf           out    0x3f, r24    ; 63
    109c:    08 95           ret

60 lines.

Assembly takes one or two lines, and is proportionally faster.

Meanwhile, I just spent three days tracking down a compiler error--
the compiler insisted (0xff & 1) = 254.  It was no fun tracking down,
and ultimately took a workaround.

Cute system, horrible documentation.  I'm afraid it sets a lot of kids
off on the wrong foot, hacking instead of thinking.

YMMV.

Cheers,
James Arthur

Re: Arduino / compilers on uC
On 07/02/17 10:43, snipped-for-privacy@yahoo.com wrote:
Quoted text here. Click to load it

Yes, it's horrid, but the assembler version doesn't do the same thing.
The digitalWrite function looks up a pin mapping table in flash
in order to create an artificial portability across Arduino versions.
Accessing flash is awkward because it's Harvard arch. It's a stupid
thing to want to do - it could be done at compile time using C++
inlines and templates - but the compiler does a fairly decent job of it.

Quoted text here. Click to load it

I don't believe you. Show us your code and your compiler version.
I bet you did (0xFF & ~1).

Clifford Heath.


Re: Arduino / compilers on uC
On 02/06/2017 06:58 PM, Clifford Heath wrote:
Quoted text here. Click to load it

Something that low level would have to be an error in gcc's own handling  
of bitwise operators, which seems...unlikely

Re: Arduino / compilers on uC
On Monday, February 6, 2017 at 6:58:13 PM UTC-5, Clifford Heath wrote:
Quoted text here. Click to load it


It's pretty messy to document, but the gist is that I wanted to toggle
a boolean flag with the statement

  flg = flg ? false : true;

 where 'true' == 1, 'false' == 0, Arduino-defined.

It didn't work--the variable was assigned either 0xfe, or 0xff.

Boolean on the AVR is an unsigned byte, flg was initialized to 0xff,
from blank EEPROM (as expected, prior to storing user parameters).

When simple statements didn't work as expected, I added a bunch of print
statements to diagnose the problem (below, with output).

You can see that, with 'boolean' type, output lines 6a., 6b., 7a., 7b.
do not give the expected results.

If I change
 11.  w = (U.dat.flg) ? true : false; to
 11.  w = (U.dat.flg) ? false : true;

and w=0xff, line 13. reports that (w & 0x1) == 254.

The upshot was that the compiler generates different code for a 'boolean'
and a 'uint8_t', even though they're both supposed to be unsigned char.

Either type should've been fine for my purposes. Both should've worked.
I tried various gimmicks like casts, forcing conversions, and assigning
to int or word types to try forcing the compiler to treat values
differently, to no avail.


Source:
 1.   int b,c,i;
 2.   word w;
 3.   float v;
 4.
 5.    Serial.print(F("  1. 'true' = ")); Serial.print(true,HEX); Serial.print(F("  2. 'false' = ")); Serial.println(false,HEX);
 6.    Serial.print(F("  3. 'i = true' =")); Serial.print((i = true),HEX); Serial.print(F(" 4. 'w = false' =")); Serial.println((w = false),HEX);
 7.    Serial.print(F("  5. Before toggle, U.dat.flg = ")); Serial.println(U.dat.flg, HEX);
 8.
 9.    i = (int) U.dat.flg;
10.    Serial.print(F(" 6a. i = (int) U.dat.flg =")); Serial.println(i,HEX);
11.    w = (U.dat.flg) ? true : false;
12.            
13.    Serial.print(F(" 6b. After assignment by '?' to 'true' : 'false', w = ")); Serial.println(w,HEX);
14.
15.    if (U.dat.flg) {
16.          w = true;
17.     } else {
18.         w = false;
19.    }
20.
21.     Serial.print(F(" 6c. After if-then assignment to 'true' or 'false', w = ")); Serial.println(w,HEX);
22.          
23.     Serial.print(F(" 7a. i & 1 = "));  Serial.println((i & 1), HEX);
24.     Serial.print(F(" 7b. w & 1 = "));  Serial.println((w & (word)1), HEX);
25.          
26.     Serial.print(F(" 8a. (i & 0x1u) = "));  Serial.println((i & 0x1u), HEX);
27.     Serial.print(F(" 8b. (w & 0x1) = "));  Serial.println((w & 0x1), HEX);
28.     Serial.print(F(" 8c. (0xff & 0x1) = "));  Serial.println((0xff & 0x1), HEX);


=== Output with U.dat.flg declared 'boolean'===
  1. 'true' = 1  2. 'false' = 0
  3. 'i = true' =1 4. 'w = false' =0
  5. Before toggle, U.dat.flg = FF
 6a. i = (int) U.dat.flg FF%

->---> 6b. After 'w = (U.dat.flg) ? true : false', w = FF <--- should be 0x1!!!

 6c. After if-then assignment to 'true' or 'false', w = FF  <--- should be 0x1 !!
 7a. i & 1 = FF  <--- should be 0x1 !!
 7b. w & 1 = FF  <--- should be 0x1 !!

 8a. (i & 0x1u) = FF  <--- should be 0x1 !!
 8b. (w & 0x1) = FF  <--- should be 0x1 !!
 8c. (0xff & 0x1) = 1


=== Output with U.dat.flg declared 'uint8_t'===
  1. 'true' = 1  2. 'false' = 0
  3. 'i = true' =1 4. 'w = false' =0
  5. Before toggle, U.dat.flg = FF
 6a. i = (int) U.dat.flg FF%

---> 6b. After 'w = (U.dat.flg) ? true : false', w = 1 <--- 1 = correct.

 6c. After if-then assignment to 'true' or 'false', w = 1
 7a. i & 1 = 1
 7b. w & 1 = 1

 8a. (i & 0x1u) = 1
 8b. (w & 0x1) = 1
 8c. (0xff & 0x1) = 1


Cheers,
James Arthur

Re: Arduino / compilers on uC
On 02/06/2017 09:30 PM, snipped-for-privacy@yahoo.com wrote:
Quoted text here. Click to load it

"boolean" is not an ISO standard C++ data type - use "bool."

Or include <stdbool.h> if you want to use "boolean" and it should behave  
as expected



Re: Arduino / compilers on uC
On Monday, February 6, 2017 at 9:43:23 PM UTC-5, bitrex wrote:
Quoted text here. Click to load it

"bool" is what I started off with, gives the same result as "boolean."
I switched to "boolean," since that was listed in Arduino's reference
page, and, having made it part of their environment, one would hope
they've made full provision for it.

https://www.arduino.cc/en/Reference/HomePage

When that didn't work, I also quit trusting the values of 'true' and
'false', which is why I started specifying numerical values, all to
no effect.

This is a lot of abstraction -- it's a byte, nothing more.

Quoted text here. Click to load it

Cheers,
James Arthur

Re: Arduino / compilers on uC
On 02/06/2017 10:02 PM, snipped-for-privacy@yahoo.com wrote:
Quoted text here. Click to load it

This have any effect?

#ifdef __cplusplus
     typedef bool boolean;
#else
     typedef uint8_t boolean;
     #define false 0
     #define true !false
#endif

The text of the bug report said the Arduino libraries futzed around with  
the boolean definitions to support C code in the core or somethin'

Re: Arduino / compilers on uC
On Monday, February 6, 2017 at 11:26:26 PM UTC-5, bitrex wrote:
Quoted text here. Click to load it


It had the effect of scaring me! Who knows what havoc it might wreak
changing assumptions throughout all their libraries & packages! :-)

I'm pretty sure I don't want to re-define uint8_t to boolean--that
would set my program back to the error condition.  Plus we already
know that 'bool' is broken in my context--I used up one of my AVR's
10,000 lifetimes to confirm that for you.

I appreciate the tips, but I'm satisfied I've solved the instant problem.
I've got hardware to get working, that's my main task.

Quoted text here. Click to load it

Yes, there's a lot of that going on.  It's charming on the one hand,
and terrifying on the other. ;-)

Thanks again,
James Arthur

Re: Arduino / compilers on uC
On 07/02/17 13:30, snipped-for-privacy@yahoo.com wrote:
Quoted text here. Click to load it

Thanks for trying anyway... though you don't show the generated
assembly code, but didn't provide clean enough code for me to do
it either.

Hint: use "gcc -S -fverbose-asm" to get the assembly code into
<file>.s with the original C code in comments.

But see below...

Quoted text here. Click to load it

I suspect that the EEPROM is operating in "write more zeroes" mode.
Do you get the same problem where the target is not EEPROM?

Clifford Heath.

Quoted text here. Click to load it


Re: Arduino / compilers on uC
On Monday, February 6, 2017 at 9:55:52 PM UTC-5, Clifford Heath wrote:
Quoted text here. Click to load it

The "clean" code was a simple assignment.  All the rest of the mess is a
pile of debugging print statements, using the awkward functions provided
for that purpose.

The generated code is even messier, disassembled from the .elf file.

Booleans, and bools work fine elsewhere in the program, substituting for
one another, doing math, logic, comparisons, and accessing this same
problematic variable.  AFAICT it's only this one area in my code--and only
a few statements--where 'bool' and 'boolean' misbehave.

Quoted text here. Click to load it

Can't. Tried. The Arduino IDE won't let you.  It compiles and links,
including includes and header files madly, doing God knows what, then
deletes the evidence.  It took a miner's hat and a gas lamp to disassemble
what I did.

I tried running gcc from the command line, but I couldn't ever make it
happy.

Quoted text here. Click to load it

That's not the case.  I loaded 'U.dat.flg' from EEPROM, which initializes
U.dat.flg to 0xff. All operations thereafter are in RAM.

Perhaps the 'boolean' type never anticipated a variable being assigned
an illegal value (neither 1 nor 0) in the first place.  Dunno.

A snip of the disassembled code follows.

The two cases use different print() calls, indicating the compiler regards
the expression results as different types, even though they ought to all
be unsigned bytes of whatever type you'd like to call 'em.

Note that the assignment
   w = (U.dat.flg) ? true : false;

generates different code in the two cases, and that different Serial.print()
routines are called.  It might be that one of those print calls used in
the 'boolean' case trashes R1 where its counterpart in the 'uint8_t'
case doesn't.  I don't know.

Like I said before, abstractions piled on abstractions--the compiler's not
protecting me, it's in the way.  But it'll all be sweet once it's done,
and easy for the customer to maintain.

Cheers,
James Arthur

============= 'boolean' (does not work) ==================
Serial.print(F("  5. Before toggle, U.dat.flg = "));
    203e:    86 e4           ldi    r24, 0x46    ; 70
    2040:    9c e0           ldi    r25, 0x0C    ; 12
    2042:    0e 94 6c 0b     call    Serial.print(F("<string>"))

Serial.println(U.dat.flg, HEX);
    2046:    80 91 94 01     lds    r24, U.dat.flg    ; 0x800194 <UserSetupTable+0x54>
    204a:    60 e1           ldi    r22, 0x10    ; 16
    204c:    70 e0           ldi    r23, 0x00    ; 0
    204e:    90 e0           ldi    r25, 0x00    ; 0
    2050:    0e 94 5c 0c     call    0x18b8    ; 0x18b8 <_ZN5Print7printlnEii.constprop.16>

i = (int) U.dat.flg;
    2054:    c0 90 94 01     lds    r12, U.dat.flg    ; 0x800194 <UserSetupTable+0x54>
    2058:    d1 2c           mov    r13, r1

Serial.print(F(" 6a. i = (int) U.dat.flg ="));
    205a:    8d e0           ldi    r24, 0x0D    ; 13
    205c:    9c e0           ldi    r25, 0x0C    ; 12
    205e:    0e 94 6c 0b     call    Serial.print(F("<string>"))

Serial.println(i,HEX);
    2062:    60 e1           ldi    r22, 0x10    ; 16
    2064:    70 e0           ldi    r23, 0x00    ; 0
    2066:    c6 01           movw    r24, r12
    2068:    0e 94 5c 0c     call    0x18b8    ; 0x18b8 <_ZN5Print7printlnEii.constprop.16>

w = (U.dat.flg) ? true : false;
    206c:    e0 90 94 01     lds    r14, U.dat.flg    ; 0x800194 <UserSetupTable+0x54>
    2070:    f1 2c           mov    r15, r1

Serial.print(F(" 6b. After 'w = (U.dat.flg) ? true : false', w = "));
    2072:    8d eb           ldi    r24, 0xBD    ; 189
    2074:    9b e0           ldi    r25, 0x0B    ; 11
    2076:    0e 94 6c 0b     call    Serial.print(F("string"))

Serial.println(w,HEX);
    207a:    c7 01           movw    r24, r14
    207c:    0e 94 47 0e     call    Serial.println(word R25:R24,HEX)

============= uint8_t (works) ==================
Same as above, except U.dat.flg is defined as 'uint8_t', and longer text
in the print statements has moved the addresses down slightly. Setting
this version to back 'boolean' recreates the error, though--the error is  
executable-position independent.

Serial.print(F("  5. Before toggle, U.dat.flg = "));
    206e:    86 e4           ldi    r24, 0x46    ; 70
    2070:    9c e0           ldi    r25, 0x0C    ; 12
    2072:    0e 94 6b 0b     call    Serial.print(F("<string>"))

Serial.println(U.dat.flg, HEX);
    2076:    60 e1           ldi    r22, 0x10    ; 16
    2078:    70 e0           ldi    r23, 0x00    ; 0
    207a:    80 91 94 01     lds    r24, 0x0194    ; 0x800194 <UserSetupTable+0x54>
    207e:    0e 94 19 0c     call    0x1832    ; 0x1832 <_ZN5Print7printlnEhi.constprop.19>

i = (int) U.dat.flg;
    2082:    10 91 94 01     lds    r17, 0x0194    ; 0x800194 <UserSetupTable+0x54>
    2086:    c1 2e           mov    r12, r17
    2088:    d1 2c           mov    r13, r1

Serial.print(F(" 6a. i = (int) U.dat.flg ="));
    208a:    8d e0           ldi    r24, 0x0D    ; 13
    208c:    9c e0           ldi    r25, 0x0C    ; 12
    208e:    0e 94 6b 0b     call    Serial.print(F("<string>"))

Serial.println(i,HEX);
    2092:    60 e1           ldi    r22, 0x10    ; 16
    2094:    70 e0           ldi    r23, 0x00    ; 0
    2096:    c6 01           movw    r24, r12
    2098:    0e 94 4d 0e     call    0x1c9a    ; 0x1c9a <_ZN5Print7printlnEii.constprop.4>

w = (U.dat.flg) ? true : false;
    209c:    ee 24           eor    r14, r14
    209e:    e3 94           inc    r14
    20a0:    f1 2c           mov    r15, r1
    20a2:    80 91 94 01     lds    r24, 0x0194    ; 0x800194 <UserSetupTable+0x54>
    20a6:    81 11           cpse    r24, r1
    20a8:    02 c0           rjmp    .+4          ; 0x20ae <main+0x370>

Serial.print(F(" 6b. After 'w = (U.dat.flg) ? true : false', w = "));
    20aa:    e1 2c           mov    r14, r1
    20ac:    f1 2c           mov    r15, r1
    20ae:    8d eb           ldi    r24, 0xBD    ; 189
    20b0:    9b e0           ldi    r25, 0x0B    ; 11
    20b2:    0e 94 6b 0b     call    Serial.print(F("<string>"))

Serial.println(w,HEX);
    20b6:    c7 01           movw    r24, r14
    20b8:    0e 94 60 0e     call    0x1cc0        ; 0x1cc0 <_ZN5Print7printlnEji.constprop.3>

Re: Arduino / compilers on uC
On 07/02/17 15:00, snipped-for-privacy@yahoo.com wrote:
Quoted text here. Click to load it

I did it once, forget how, but this seems to cover the technique:
https://github.com/sudar/Arduino-Makefile

You can also add compiler options in a config file; look for a file
in your Arduino install whose pathname ends in
.../hardware/arduino/avr/platform.txt

Quoted text here. Click to load it

Ok, well, I'm surprised. That would not easily happen through normal
gcc development processes, but I suppose that the Arduino team are
pretty slipshod in many other ways, so...

Clifford Heath.

Re: Arduino / compilers on uC
On 07/02/17 05:00, snipped-for-privacy@yahoo.com wrote:

Quoted text here. Click to load it

How is the type of U (and in particular, U.dat.flg) defined?  I assume
it is "boolean", since this explains the effects you are seeing.

The Arduino makes "boolean" a typedef of "bool", which is a standard C++
type.  "true" and "false" are built into C++, and are not
Arduino-defined.  (Personally, I really dislike the way Arduino tried to
"hide" or "simplify" C++.)

If the compiler knows that something is a boolean type, then it can
assume that it can only ever be 1 (true) or 0 (false).  Anything else is
undefined behaviour.  So if you have declared U.dat.flg to be "boolean"
and put 0xff in it, you have lied to the compiler.

When the compiler sees "w = (U.dat.flg) ? true : false;", it /knows/
that U.dat.flg is already either 1 or 0 - because you have told it so,
in your declaration of the type of U.dat.flg.  If it is 1 (true), then w
should be set to true - if it is 0 (false), then w should be set to
false.  Thus the statement can be simplified to "w = U.dat.flg".

Similar reasoning gives you the rest of your results.


The answer is to declare U.dat.flg as "uint8_t", since it can hold any
value in that range.


Re: Arduino / compilers on uC
On Tuesday, February 7, 2017 at 4:29:06 AM UTC-5, David Brown wrote:
Quoted text here. Click to load it

'boolean', 'bool', or 'uint8_t', as explained in detail above.
  
Quoted text here. Click to load it

It's not my job to guarantee that Atmel/Microchip pre-initialize the EEPROM
to please gcc.

But I'd tried to compensate by immediately directly writing '0' or '1' to
the variable, and other operations that should've brought it to a legal
condition.  The compiler doesn't follow those instructions, instead
either optimizing the operations out entirely, or only toggling the
lsb.

Quoted text here. Click to load it

Which is what the compiler did, and, in its wisdom, wouldn't allow me
to write 'true' or 'false' to properly initialize a boolean.

Quoted text here. Click to load it

Already done & described in posts above.

Cheers,
James Arthur


Re: Arduino / compilers on uC
On 07/02/17 16:39, snipped-for-privacy@yahoo.com wrote:
Quoted text here. Click to load it

I'm trying to help here - giving the relevant information will help me
help /you/.  And giving it succinctly rather than buried within pages of
generated assembly would be far more useful.

Quoted text here. Click to load it

It is /your/ job to know the meaning of a type in a programming language
before you use it.

The Arduino folk might not make that as easy as it should be, by
encouraging non-standard types like "boolean" without proper
documentation (and even worse, where the semantics apparently vary
according to versions).  Still, it is /your/ job.

Feel free to ask here, or in comp.lang.c or comp.arch.embedded to get
help on the matter.  Just remember to give the information people ask
you for, and to accept that it might be /your/ misunderstanding rather
than blaming the compiler.

Quoted text here. Click to load it

That is correct behaviour on the part of the compiler.  The compiler's
job is to generate efficient code on the assumption that the code it is
given is correct C (or C++ in this case).  If you sneak a value of other
than 0 or 1 into something declared as "bool", you are breaking your
side of the bargain.  The compiler is not omnipotent and cannot read
your mind or guess what you /really/ meant.

And again, I fully understand how you can make this mistake, how the
Arduino stuff makes it difficult, and how some aspects of the C language
can be hard to understand.  That's why I encourage you to /ask/ about
it, giving the relevant information, rather than throwing blame around.

Quoted text here. Click to load it

If U.dat.flg is declared as "bool", then the compiler knows that
U.dat.flg is already a properly initialised bool.  You would not want
the compiler to generate a series of unnecessary instructions doing
tests and jumps simply to assign from one bool to another.

You lied to your compiler, albeit unknowingly and unintentionally.  It
bit you.  That's what happens when you lie to your compiler.

Quoted text here. Click to load it

Yes, but hopefully you now understand that the compiler did not make any
mistakes - the error was in your code.  And you know that you have not
just "found a workaround" - you understand the problem, and understand
the correction to your code error.



Re: Arduino / compilers on uC
On Wednesday, February 8, 2017 at 6:24:32 AM UTC-5, David Brown wrote:
Quoted text here. Click to load it

I used a 'bool' (then a 'boolean') to represent a boolean quantity. Isn't
that the point of having a boolean type?

If the compiler's code absolutely depends on a variable having certain
values and no others, the compiler should take steps to ensure that the
variable contains a legal value.  Instead, it prevented me initializing
the variable to a known condition.

That's a common circumstance--variables aren't initialized to known
conditions when power's applied.

What's the value in having a 'boolean' if you have to ultimately use
bizarre, unsigned, faked, phony types to ultimately represent it with
a byte anyhow?

Quoted text here. Click to load it

No, the compiler *is* at fault.  It optimized out the operation

 w = (U.dat.flg ? true : false;)

substituting: U.dat.flg ==> w.

          1          2         3
 w = (U.dat.flg) ? (true) : (false);

To do that is to assume expression #1 (U.dat.flg != 0) is equivalent to, has
the same range of values as, and is interchangeable with expressions of type
'boolean' #2 & #3.

That's wrong.

Cheers,
James Arthur

Re: Arduino / compilers on uC
On 10/02/17 03:36, snipped-for-privacy@yahoo.com wrote:
Quoted text here. Click to load it

I agree. This generated code should/could be more defensive.
But it's not incorrect, as David has been patiently explaining.

Quoted text here. Click to load it

That's true, but not in C. The startup code (before main) is expected
to initialize all global and static variables to zero, and the
compiler is entitled to expect that. (Startup code is not part
of the compiler).

If you use a union over multiple types, you are entirely responsible
for your program's type safety.

Clifford Heath

Re: Arduino / compilers on uC
On 09/02/17 22:15, Clifford Heath wrote:
Quoted text here. Click to load it

No - "more defensive" means "less efficient".  I would not want a
compiler to generate slow and inefficient code on the basis that some
programmer somewhere might have made a mistake.

Quoted text here. Click to load it


Re: Arduino / compilers on uC
On 09/02/17 17:36, snipped-for-privacy@yahoo.com wrote:
Quoted text here. Click to load it
<snip>
Quoted text here. Click to load it

That is the point of "bool", yes.  But you took something that you did
not know to be a valid bool, and told the compiler that it /was/ a valid
bool - that's a lie.

An alternative way to think about this is that the data in the eeprom is
external data from an unknown source.  You don't know it is valid until
you have checked it.

If you are writing a web application, and it asks the user for a name,
you don't assume that they have entered a valid name.  You /check/ the
entered data - you don't pass it on to a database query unless you want
to create an SQL injection attack.  The data in the eeprom is the same -
it is unchecked unknown external data, and you have to confirm that it
fits your requirements before using it.  You can't simply /declare/ to
the compiler that it fits your requirements - you have to check it.

Quoted text here. Click to load it

The compiler /will/ take steps to make sure that a bool variable holds a
legal value - it does so every time it stores something that is not
necessary legal.  So if you have a uint8_t item that you are storing
into a bool, the compiler will convert any non-zero value into 1 before
storing it.  But in your code, you have told the compiler that you
already have a checked, valid bool value - so a simple copy is all the
compiler needs to do to be absolutely sure the bool is valid.

Quoted text here. Click to load it

It removed code that was clearly unnecessary based on the information
you gave the compiler.

Quoted text here. Click to load it

Variables (with program lifetime) are /always/ initialized to a known
condition at the start of main(), as far as C is concerned.  They are
either initialised to an explicit value, or implicitly to 0.  If the
startup code (as run between reset and main()) does not do this, then
that code is lying to the compiler.  (I have seen tools that do this -
it's a serious PITA.)  Local stack data and heap data are not
initialized, and the compiler knows this too.

Quoted text here. Click to load it

You don't have to do anything of the sort.  You simply have to treat
external unknown data as having any value that can physically fit in the
space.  So if you are mapping data from an eeprom, then use uint8_t for
the bytes.  Then you can assign that to a bool type if you want.

Alternatively, you can have a mechanism that checks and corrects the
eeprom data once, then you know it is correct.  For example, at program
startup you could read the eeprom data as a uint8_t, and if it is not a
valid bool, then write a 0 or 1 to it.  For my eeprom data, I will often
have a checksum to be sure that the data is valid - when starting up, I
verify the checksum.  If it is correct, then my eeprom data is safe to
use (bools, enums, and all).  If it is incorrect, then I fill the eeprom
structure with a valid default set of values.

Quoted text here. Click to load it

You have told the compiler that U.dat.flg contains either 0 or 1 - you
did this when you declared its type to be "bool".  You are asking the
compiler to take this value, and if it is 1 then it should store 1 in w,
and if it is 0 then it should stor 0 in w.  Implicitly, you are also
saying that if U.dat.flg is /not/ 0 or 1, then the compiler can do what
it wants - including launching nasal daemons.  That's how programming
works - it is a contract between the programmer and the compiler.  When
you break your side of the bargain, don't expect the compiler to perform
miracles.




Re: Arduino / compilers on uC
On Monday, February 6, 2017 at 11:00:56 PM UTC-5, snipped-for-privacy@yahoo.com wrote:
Quoted text here. Click to load it

  
[...]

Here's the problem--in the 'boolean' case, the compiler has optimized out
my assignment of 'true' or 'false' entirely, and has reasoned that it can
simply directly load the original, illegally 0xff-valued U.dat.flg into
(word) w (=R15:R14):
  
Quoted text here. Click to load it

The compiler thus defeats my instructions to substitute 'true' or
'false' for whatever odd value U.dat.flg happened to inherit from
the EEPROM.

If I reverse the positions of 'true' and 'false' in that statement
creating a toggle--the original code--the compiler only toggles the lsb,
leaving me with w = 0xff, or 0xfe, both still illegal values.


By contrast with type 'uint8_t', the compiler generates an actual 0x1,
then conditionally assigns that, or 0x0, as the result of the expression:

Quoted text here. Click to load it

Cheers,
James Arthur

Re: Arduino / compilers on uC
On 07/02/17 17:05, snipped-for-privacy@yahoo.com wrote:
Quoted text here. Click to load it

When you program in C (or almost any other programming language, except
assembly), you do not give the compiler a list of instructions to be
turned into object code.  You give a sequence of instructions for an
"abstract machine", and the compiler will generate code that has the
same visible effect as though it followed the instructions.

It is sometimes a subtle distinction, but it is an important one.  It
means that the compiler can use its knowledge of the program and its
state in order to remove or simplify source code.  It can re-arrange
source code in many ways.  It can remove or re-order anything that does
not affect /visible/ results - volatile accesses, file I/O, program
start and stop, and calling external functions whose effect is unknown
(since such functions might have other visible effects).

By declaring U.dat.flg to be bool, you have given the compiler
information - and it uses that information to generate better code.  If
that information was not correct, you should not have given it to the
compiler.

Quoted text here. Click to load it


Site Timeline