Arduino / compilers on uC

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.

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.

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.

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.

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.

Reply to
David Brown
Loading thread data ...

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.

Reply to
David Brown

No, they cannot. 1 is the only valid "true" value that can be assigned to a bool (or _Bool in C). If you write "bool b = 23;", the compiler /must/ assign 1 to b (or act as though it assigned 1 to it - optimisations may let it do something else as long as the effect of the program is as though it assigned 1 to b).

This is the key difference between a "bool" (_Bool) and just using a uint8_t or char to store your flags.

As I heard recently, "type casting" is what happens to film stars - "casting" is what you do in C.

But no, casting your bool to a byte (uint8_t) will not help. The compiler knows the possible values of the bool (0 or 1), and thus knows the possible values the uint8_t will have after the cast (0 or 1).

That is a completely different matter. A conditional statement ("if", "while", etc.) compares its argument to 0 (in C) or "contextually converts to bool" (in C++) - thus any non-false value is considered "true".

Reply to
David Brown
,
.

Back in the late '70s (iirc) the Forth standard changed to make TRUE = -1 instead of 1, causing massive breakage. The rationale was that on a twos-c omplement machine that made every bit of the word 1, so you could use TRUE and FALSE in bitwise operations too.

Nice idea, if they'd thought of it the first time round. :(

Cheers

Phil Hobbs

Reply to
pcdhobbs

It is not entirely unreasonable to standardise on -1 for "true". But C (and C++) standardised on 1, and that's the way it is. (It's a better choice anyway - it has the same representation in all integer types, no matter what size or signedness.)

Reply to
David Brown

The ATMega project I'm working on now will probably be a couple thousand lines of code when it's all done. You can definitely do a lot with "only" 32k...

Reply to
bitrex

Why scornful? What's wrong with cushy? Abstractions and working at a high-level is great, the compiler does a great job of crunching it down to size. The example given by the OP of the assembler output of function used to write a pin is a pathological one, as the C++ code was written to be maximally generic.

If you just want something fast and simple like a basic port write or math function in my experience it makes little difference if you write the code in C or ASM; the compiler is so good that it's very hard to beat the ASM it generates in most circumstances.

Reply to
bitrex

Right - my last MSP430 project was 4000 lines of C, which fit in the 4K flash.

Reply to
Clifford Heath

The ratio between "difficulty" and "pride" has limits. Some people get inordinately proud of their crappy little Arduino project, even though it was piss-easy and badly done. I scorn the pride, not the success.

Hey, I'd do the same, I like to make things cushy too. I just try not to be indecently proud of my successes.

I don't think it is C++, just C. I investigated the same function a few months back, and recall finding the source code. The size of the function is because of the need to use special opcodes to extract entries from Flash; it's not directly addressable because of the Harvard architecture.

My bugbear with the C in this case is that there is a bit-set and bit-clear instruction that only has a 5-bit addressing range. If the C compiler doesn't know the address, it will emit a much longer instruction instead, and the linker doesn't optimize that. When I wanted to do it in a C++ template, I couldn't find a way to cleanly tell the compiler that the register structure has a fixed physical address without hiding that in a separate source file; then it emits the long-form opcode.

Clifford Heath.

Reply to
Clifford Heath

formatting link

Reply to
Lasse Langwadt Christensen

To an extent, true. More often my aim in using a pre-written function is to avoid repeating the work, not avoiding understanding the task.

'C' was conceived as a portable assembly language, so it's bizarre and ironic that this portable 'assembly' doesn't guarantee the size of its basic variables--that's one of the most basic elements of assembly-level programming.

Your fears were justified. I think this foray will still be a net plus-- the customer is already using the Arduino, and will be comfortable maintaining the code.

But it is a little scary having this 1.1kV hardware on my desk (next to my keyboard) under Arduino control. Gladly, I included several safeties.

That's a more hopeful take on it, thanks.

Cheers, James Arthur

Reply to
dagmargoodboat

'C' leaving so much to be defined later outside the language has had dizzying effect, all this flowing from a coupla' guys trying to keep their simple hacking tool simple.

Simple choices can have immensely complex ramifications.

Cheers, James Arthur

Reply to
dagmargoodboat

No, C was never a "portable assembly language". Some people think so - they are wrong, and the result is that they are unable to write good C code because they completely misunderstand the language.

C was designed to remove the need to write so much code in assembly. It was designed to /replace/ assembly for many purposes, not to be a new kind of assembly.

One of the points of C is that it isolated most programmers from the need to deal with details such as the size of its basic types, thus making it easier to write code that works on a wide variety of systems. At the same time, it placed a strong emphasis on "implementation defined" behaviour - the C language does not define the sizes of its basic types, but any given C implementation /does/ define them. So you can write code that is portable across many systems, and you can also write code that is dependent on the details of a particular target. (C99 included types that make it easier to write portable code that needs to rely on some of these details.)

It is a myth that C is a "portable assembly language" or anything of the sort.

It is a misunderstanding to think that when using C, you do not have guarantees about the sizes of basic types or their representation.

Reply to
David Brown

Well you're right, I've been loosely referring to the development environment as a monolithic thing, which we all know it is not.

So I suppose I should've phrased my original lament as "look at the systems upcoming programmers are relying on to generate code these days."

"Those who say, don't know; those who know, don't say." --Lao Tzu

There was a fair load from calling C++ constructors, also.

That would be a magnanimous gesture. Perhaps the biggest service Arduino has done is providing a platform whereby one person can make a contribution like that, and benefit millions. That's incredible leverage.

Let's hope mankind uses all of this leverage to make the world a better, safer place, and not for interfacing IEDs with cellphones.

Cheers, James Arthur

Reply to
dagmargoodboat

nope. C per definition has 0 == FALSE, and TRUE is anything different from FA LSE.

Bye Jack

Reply to
jack4747

I know all that. I meant to illustrate and quantify by example how all these ingenious attempts to coddle and insulate users actually get in the way.

I wasn't asking "How can I make efficient code on an Arduino?," but drawing attention to the fact that neophytes using the stock tools are, naively, working through layers of abstraction, and do *not* get efficient code.

No slight to gcc intended.

Cheers, James Arthur

Reply to
dagmargoodboat

OK. Your original post read as quite clearly blaming the compiler (and indeed, railing against all compilers), but maybe it didn't come across as you intended.

And I agree that the Arduino does not do an ideal job in making microcontroller programming easy for newbies. It makes some easy tasks easier, but by hiding details of the language while still relying on them, it makes fault-finding or medium-level tasks harder, and advanced tasks almost impossible.

Reply to
David Brown

You are wrong - and if you don't believe me, look it up in the C standards.

C has no identifier "FALSE", nor an identifier "TRUE" - and if it did, the "TRUE" would have to be defined to a particular fixed value.

There are three contexts in which C (and C++, which is the language in question) have a concept of "true" or "false".

  1. The boolean types. In C++, this is "bool" - in C from C99 onwards, it is "_Bool". In C++, "bool" is the type and "true" and "false" are keywords. In C, "_Bool" is the type and "true" and "false" are macros defined to 1 and 0 respectively, with "bool" being a macro defined to "_Bool" (all this is in ). Prior to C99, C has no boolean type and no true or false identifiers.

The type _Bool (or bool) may only store 0 or 1. If you convert from another type to "bool", then any value that does not compare equal to 0 is converted to 1.

  1. The relational operators (==, !=, , =). These evaluate to 0 for false, 1 for true.
  2. Conditional statements and expressions ("if", "while", and the control clause of "for", as well as the conditional operator and the logical "not", "and" and "or" operators). In C, given "if (x)" then the condition is considered "true" if x does not compare equal to 0. In C++, x is "contextually converted to bool". Unless you are doing something weird with conversion operators, this usually means much the same thing.

So in C, false is 0, true is 1. Boolean types cannot legally hold any other value. Any time the compiler is asked to consider a non-boolean expression in a boolean context, then an expression that does not compare equal to 0 is converted to 1.

In pre-C99 C code, there is no "_Bool" type standardised (though implementations may have one as an extension). It was common to use either an "int" or an "unsigned char" for holding boolean flags, and to define "true" and "false" as macros meaning 1 and 0. Occasionally people used an enumerated type with the same effect. Then there were no guarantees about these variables being restricted to 0 and 1. And some people would define their "true" (or "TRUE") macro to be -1 instead of 1

- but that was their personal C code - it has never been part of the C language.

Reply to
David Brown

Porting C code has /always/ been very difficult, and required arcane knowledge and extreme care; start by considering "porting" from twos complement to ones complement machines.

But from the late 80s onwards it has been unsuccessfully straddling two stools: that of a general purpose high level language for applications and also for low-level near-the-silicon "system/firmware" code. Consider that multithreading behaviour is (was?) explicitly left undefined or implementation dependent, but POSIX thread implementations relied on that behaviour.

Maybe having a memory model will help, but it is astoundingly difficult to get that right across multiple architectures. Even the Java JVM's memory model was reworked in the light of experience.

Until ~1993 I vaguely followed the standards, but the eternal and /unresolvable/ "cast away constness" discussions convinced me that C (and doubly C++) was becoming a problem more than a solution.

You mustn't be able to cast away constness, since that might affect correctness. You must be able to cast away constness for some efficiency hacks and for things like debuggers.

That's unresolvable.

C++ is worse; the designers *discovered* they'd created a monstrosity where you can cause the compiler to emit the sequence of prime numbers during compilation. The designers didn't believe it until someone demonstrated it!

No, nowadays C++ is beyond mortal's comprehension, and C isn't much better.

Shame.

Presuming the software works (yes, I know), I would still be concerned about the mechanical suitability of normal arduino hardware in an industrial setting.

A rare occasion where I am optimistic ;}

Reply to
Tom Gardner

I can't fault Ritchie and Thompson for the original C concepts and limitations.

I do fault people for pushing that tool into areas where it is not fit for purpose. The committees had an impossible task, and failed.

I'd have been perfectly happy if either c/C++ had retained its focus on - low-level "firmware/system" applications, /or/ - high-level "general purpose" applications

In the event Java deservedly won the latter. I wish there was a simpler more predictable tool for the former. Makes me want to use Forth :)

Reply to
Tom Gardner

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.