Programming in C

The standard "main" function template is:

int main(int argc, char** argv) {
}

where argc is the number of program arguments, including the program name itself ,and argv is an array of c-strings (null-terminated array of char) that contain those argument.

#include <stdio.h>

int main(int argc, char** argv) {
    if (argc == 1) {
        printf("Usage: %s <your name>\n", argv[0]);
        return 1;
    }

   printf("Hallo, %s !\n", argv[1]);
}
tuxduino@mylaptop:~/tmp/x$ gcc -o halloName halloName.c 
tuxduino@mylaptop:~/tmp/x$ ./halloName
Usage: ./halloName <your name>
tuxduino@mylaptop:~/tmp/x$ ./halloName tuxduino
Hallo, tuxduino !

All of this makes sense in a pc environmente, where you have stdin, stdout and a shell passing arguments to your program. That's totally absent in an embedded environment (unless you're on raspi, of course :stuck_out_tongue: ), so main() function arguments are pointless.

dhenry:
K&R is the best book you can find on C (and one of the hardest to understand fully as well).

You keep saying that, but you never actually say what part of the book you have trouble understanding.

If it was hard to understand, it certainly wouldn't be a very good primer.

pico:

dhenry:
K&R is the best book you can find on C (and one of the hardest to understand fully as well).

You keep saying that, but you never actually say what part of the book you have trouble understanding.

If it was hard to understand, it certainly wouldn't be a very good primer.

Mmm - I do find it somewhat strange that one would recommend a book saying it was the hardest to fully understand.

I just feel as if a book aimed solely at C in an embedded environment will serve me better, for example - Tuxuino, thank you for your reply - but none of the post makes sense to me, and if I'm going to keep reading things like that I need not learn right now, I may end up being distracted from what I set out to do.

Looks like there are books about embedded C using AVRs!

jtw11:
It may sound like a stupid question; but what do you mean by no parameters to main?

Clearly we have many ways in inputting things to an MCU?

When a C program is run under an OS (Linux etc.) command line parameters can be passed to the program (e.g. in "sort mylist", if the program was called "sort", the first command line parameter would be "mylist"), and in the program sort.c sees these command line parameters as parameters passed to main() (which is the "top level" function that the program starts in.)

Since you can't pass parameters to main() in an embedded application (the program just starts up at power up without any user interaction), this avenue of communication isn't open. The program, once running, can get potentially get inputs from a variety of other input sources however.

One of the "Arduinoisms" you may have just encountered is that in an Arduino sketch, you don't actually start in a main() function. (main() is actually there in the background, but hidden away from your "sketch" program.) Instead, you need to write two functions that are called by main() in the background. They are:

void setup()
{
}

and

void loop()
{
}

The main() function (that you don't see) that is calling these functions looks like this:

int main()
{
  setup();
  for(;;) 
     loop();
}

which means that the setup() function (that you write) is called once at the start of execution, but your loop function is called repeatedly after that.

jtw11:
Would anybody have any recommendations for a book aimed specifically at embedded C, rather than C used in a 'normal' PC environment? Things such as the above I fear will complicate matters, I'm never one just to accept "that's how it is" and move on, so will always want to know why things that appear to make no different to my code are there.

C in an embedded environment is a subset of C in a non-embedded environment. You read a general C book (like K&R) and just have to understand that some things just won't make sense in an embedded environment (e.g. file IO functions like fopen() etc. won't work because there is no file system for them to operate on!)

The language is the same, however (modulo some of the Arduino idiosyncracies.) In the embedded world, the equivalent to "hello world" is the "blink" program. Have a look for it in the example programs included with the Arduino IDE. Probably the most direct way forward is to be reading the Arduino example code, experimenting with it, and then referring to the K&R to understand the C language constructs they employ.

I suspect you will make rapid progress. :slight_smile:

Thank you Pico regarding how the Arduino IDE combines setup and loop into one main.

Regarding starting at the blink sketch, I've actually written some fairly complex programs that work bug free in the Arduino IDE such as; temperature dependant motor control using H bridges of discrete components with LCD interfacing, tachometer (albeit limited in speed range due to overflows that I need to sort out) etc etc.

However, I just felt that maybe because Arduino was my first intro to programming, now I've got a grasp on the world of it, I should start again with 'pure' C, then move onto 'pure' C++.

Maybe I should take some of my Arduino programs, and try to replicate that exact behaviour using pure C in Atmel Studio, whilst referring to K&R.

jtw11:
Maybe I should take some of my Arduino programs, and try to replicate that exact behaviour using pure C in Atmel Studio, whilst referring to K&R.

You'll find that (conceptually) there there isn't that much to do, outside of what we've already discussed.

You'll have to

a) provide your own main function.
b) use different #include directives for the different environment
c) write your own function prototypes (just function declarations that you put near the start of your program to simplify things for the compiler when it comes across a call to a function that it hasn't yet seen in the source file.)
d) change to the use of "bool" instead of "boolean"

and

e) (this is the biggy) either port across any of the libraries you have been using to your new programming environment, adapt your programs to use any equivalents written for the new environment, or develop your own equivalent libraries from scratch.

The thing about e), is that although Arduino is basically C/C++, a lot of the Arduino C/C++ code base in the libraries (e.g. "Ethernet", "SPI", etc.) relies on the "wiring" library functions (e.g., delay(), digitalWrite() etc.) These "wiring" functions won't be available in a standard set of C libraries -- it's actually the "wiring" library add-on that gives Arduino its "flavor" as a development environment, and it's reputation as an "easier" C programming environment for beginners.

So it's all doable, in principle. But it will be be some work porting across an Arduino sketch to a environment that doesn't include "wiring". If learning about the nuts and bolts of C is your goal, this would be a good way of doing just that. But I'd start with porting across some of the simpler programs (like "blink") first just to get your feet wet.

Hope this makes sense to you.

However, I just felt that maybe because Arduino was my first intro to programming, now I've got a grasp on the world of it, I should start again with 'pure' C, then move onto 'pure' C++.

Maybe I should take some of my Arduino programs, and try to replicate that exact behaviour using pure C in Atmel Studio, whilst referring to K&R.

I think you are missing an important point being made. The C language was invented by R of K&R to write programs in a operating system environment, unix to be exact. So C has built in features that allows it to except command line arguments from the OS when the compiled C program is called to run and optionally to return a optional error code to the OS when the C program exits. When you are dealing with the vast majority of microcontroller chips and their applications there will be no operating system running inside the chip to pass arguments to the microcontroller's compiled C program nor any way to exit back to an OS.

So while you can write programs in Atmel Studio that won't do any of the 'non-standard C/C++ modifications' that the arduino IDE preprocessor does to your sketch, there will still be no operating system for you program to interface with, so most of the examples in the K&R book will still not work as most rely of piping of data streams into and out of standalone C programs written to all operate within an underling OS.

If you really want to learn and use pure C (or C++) as it was originally designed and explained in the classic K&R book then you should be using a PC C compiler to write C programs that will run under the PC's OS be it Windows, Linux, Apple, etc. So unless you plan on getting a much more powerful ARM based development board and install some kind of operating system to run on it, any use of the C/C++ programming language has to limit itself to using just the features and methods that make sense in a typical microcontroller based 'standalone' environment. be it arduino or other platform.

Lefty

retrolefty:
The C language was invented by R of K&R to write programs in a operating system environment, unix to be exact.

Not quite accurate. Ken Thompson and Dennis Ritche firstly developed C (from an earlier language, B) in order to write the UNIX operating system.

They actually had two goes at it. The first attempt they abandoned as things got too complex in an earlier more primitive version of C they had developed. Then they introduced "structures", and that allowed the second attempt to go much more smoothly.

Once the OS was written, C was found to be quite a usable language for application programming as well, of course. So although it is more commonly used as an application development language today, it had it's origins as a systems development language. Which is undoubtedly the main reason it is still the "bare-metal" programming language of choice today.

Nerdy enough for you? :wink:

Not quite accurate. Ken Thompson and Dennis Ritche firstly developed C (from an earlier language, B) in order to write the UNIX operating system.

Not quite nerdy enough. It was developed to aid porting Unix.

AWOL:
Not quite nerdy enough. It was developed to aid porting Unix.

Nope. Writing it. If you think the first version of UNIX was written in assembly language, that is a mistake.

Pico, thanks for your reply last big reply - that was the sort of answer I'd been trying to coax out of people. Maybe I just didn't ask the right questions.

a) provide your own main function.

By this, you mean combine the Arduino setup and loop functions into one function, main? As discussed earlier? So, things like setting up pins as inputs for example, you just do inside the main? However, I will need to refer to these as ports and what not I believe instead simply of pin numbers - I need to look in to this.

b) use different #include directives for the different environment

I'm not too sure what you mean here by different directives? Do you mean for example, say I wrote my own servo library - that I'd write #include <myownservolib.h>. Or are you referring to including again, for example, standard libraries that come with Atmel Studio?

c) write your own function prototypes (just function declarations that you put near the start of your program to simplify things for the compiler when it comes across a call to a function that it hasn't yet seen in the source file.)

Again, a little lost here. A function for example would be digitalWrite?

d) change to the use of "bool" instead of "boolean"

No problem - I haven't actually used boolean all that much, so there arn't many instances to change.

Regarding point e) - I agree this seems the most important, writing or finding libraries that provide the functions such as milli() micro() etc as my codes have used these quite extensively. I need to find out how to write a library. Just on a side note, is wire.h included automatically? As I haven't included it in my codes using functions such as millis, and all works fine.

Retrolefty

I think you are missing an important point being made. The C language was invented by R of K&R to write programs in a operating system environment, unix to be exact. So C has built in features that allows it to except command line arguments from the OS when the compiled C program is called to run and optionally to return a optional error code to the OS when the C program exits. When you are dealing with the vast majority of microcontroller chips and their applications there will be no operating system running inside the chip to pass arguments to the microcontroller's compiled C program nor any way to exit back to an OS.

So while you can write programs in Atmel Studio that won't do any of the 'non-standard C/C++ modifications' that the arduino IDE preprocessor does to your sketch, there will still be no operating system for you program to interface with, so most of the examples in the K&R book will still not work as most rely of piping of data streams into and out of standalone C programs written to all operate within an underling OS.

If I've interpreted this post correctly - you're agreeing that maybe a book on writing actual embedded C for MCUs is probably going to be a better idea here?

pico:

AWOL:
Not quite nerdy enough. It was developed to aid porting Unix.

Nope. Writing it. If you think the first version of UNIX was written in assembly language, that is a mistake.

Never really searched that deep into the origins of Unix, but unless this Wikipedia article is wrong, C was developed to overcome the shortcomings of B in porting the assembly-coded PDP-7 version of Unix to a PDP-11.

Here's the relevant paragraph:

The origin of C is closely tied to the development of the Unix operating system, originally implemented in assembly language on a PDP-7 by Ritchie and Thompson, incorporating several ideas from colleagues. Eventually they decided to port the operating system to a PDP-11. B's inability to take advantage of some of the PDP-11's features, notably byte addressability, led to the development of an early version of C.

The original PDP-11 version of the Unix system was developed in assembly language. By 1973, with the addition of struct types, the C language had become powerful enough that most of the Unix kernel was rewritten in C. This was one of the first operating system kernels implemented in a language other than assembly. (Earlier instances include the Multics system (written in PL/I), and MCP (Master Control Program) for the Burroughs B5000 written in ALGOL in 1961.)

And here's the page address:

Very interesting (and nerdy) stuff :slight_smile:

pico:

AWOL:
Not quite nerdy enough. It was developed to aid porting Unix.

Nope. Writing it. If you think the first version of UNIX was written in assembly language, that is a mistake.

Well extracted from wikipedia:

Early developments

Ken Thompson and Dennis Ritchie, developers of the C programming language.
The initial development of C occurred at AT&T Bell Labs between 1969 and 1973;[3] according to Ritchie, the most creative period occurred in 1972. It was named "C" because its features were derived from an earlier language called "B", which according to Ken Thompson was a stripped-down version of the BCPL programming language.
The origin of C is closely tied to the development of the Unix operating system, originally implemented in assembly language on a PDP-7 by Ritchie and Thompson, incorporating several ideas from colleagues. Eventually they decided to port the operating system to a PDP-11. B's inability to take advantage of some of the PDP-11's features, notably byte addressability, led to the development of an early version of C.
The original PDP-11 version of the Unix system was developed in assembly language. By 1973, with the addition of struct types, the C language had become powerful enough that most of the Unix kernel was rewritten in C. This was one of the first operating system kernels implemented in a language other than assembly. (Earlier instances include the Multics system (written in PL/I), and MCP (Master Control Program) for the Burroughs B5000 written in ALGOL in 1961.)

So it says there that unix did get started as an assembly created OS?

Lefty

jtw11:

b) use different #include directives for the different environment

I'm not too sure what you mean here by different directives? Do you mean for example, say I wrote my own servo library - that I'd write #include <myownservolib.h>. Or are you referring to including again, for example, standard libraries that come with Atmel Studio?

The latter.

jtw11:

c) write your own function prototypes (just function declarations that you put near the start of your program to simplify things for the compiler when it comes across a call to a function that it hasn't yet seen in the source file.)

Again, a little lost here. A function for example would be digitalWrite?

Read your K&R or other C primer on "function prototypes". You won't have seen these in Arduino, because they are generated automatically in the sketch -> "real" C++ source file conversion stage by the Arduino IDE.

jtw11:
Regarding point e) - I agree this seems the most important, writing or finding libraries that provide the functions such as milli() micro() etc as my codes have used these quite extensively. I need to find out how to write a library. Just on a side note, is wire.h included automatically? As I haven't included it in my codes using functions such as millis, and all works fine.

Yes, the wiring stuff gets included automatically in an Arduino sketch, from the #include <Arduino.h> directive.

tuxduino:
C was developed to overcome the shortcomings of B in porting the assembly-coded PDP-7 version of Unix to a PDP-11.

Here's the relevant paragraph:

The origin of C is closely tied to the development of the Unix operating system, originally implemented in assembly language on a PDP-7 by Ritchie and Thompson, incorporating several ideas from colleagues. Eventually they decided to port the operating system to a PDP-11. B's inability to take advantage of some of the PDP-11's features, notably byte addressability, led to the development of an early version of C.

The original PDP-11 version of the Unix system was developed in assembly language. By 1973, with the addition of struct types, the C language had become powerful enough that most of the Unix kernel was rewritten in C. This was one of the first operating system kernels implemented in a language other than assembly. (Earlier instances include the Multics system (written in PL/I), and MCP (Master Control Program) for the Burroughs B5000 written in ALGOL in 1961.)

And here's the page address:

C (programming language) - Wikipedia

Very interesting (and nerdy) stuff :slight_smile:

OK, I take it back -- there was a version of UNIX in assembly language. How about that. Apologies to AWOL!

But the point remains that C was developed firstly as a systems programming language, with the practical purpose of implementing the UNIX kernel. I think one of the reasons it has lasted so well is because it grew out of the immediate need for a tool for this very practical and challenging task. Only what was needed to do the job was included. All very lean and minimalist -- no extra baggage here.

Which of the files in the Arduino package can I find out which and what .h libraries are included?

Just trying to figure out exactly what needs to be included...

Nothing needs to be included, per se.

However if you look at some of the low-level .h files which come with the IDE you will see helpful defines for things like the registers used by the processor.

As an example, one of Timer 2's registers:

#define OCR2A _SFR_MEM8(0xB3)

And 0xB3 is indeed where that register is on the Atmega328P.

You could read any book on C (or C++), just disregarding the parts where their examples interact with higher-level operating systems (like reading or writing files). And in the case of C++, disregard the part about exception handling, since that is turned off by compiler flags when the IDE compiles your sketch.

You can compile a minimal sketch:

int main ()
  {
  return 0;
  }

Quite short:

Binary sketch size: 176 bytes (of a 32,256 byte maximum)

Most of that is interrupt vectors and a bit of compiler prologue, which you can omit (as bootloaders do).

If you start fleshing out that minimal sketch you would find that it would be your job to make things like millis() work, because the timers hadn't been initialized.

jtw11:
Just on a side note, is wire.h included automatically? As I haven't included it in my codes using functions such as millis, and all works fine.

Just noticed this -- don't confuse "Wire.h" with "wiring.h".

Wire.h is a user library, implementing an I2C interface, found in the in the libraries/Wire subdirectory.

For wiring.h, you would look in the hardware/arduino/cores/arduino subdirectory.

Ah - thank you. I have only ever used wire.h once, so missed this! Thanks.