Good C programming books  - Page 1
Forum section: electronics / general

author: Jwillis
author_rank: Super Contributor
timestamp: September 26, 2019, 11:18:05 pm
content: Hey folks. I haven't done any programmming in C since the ATARI ST days (1985-1991) and I lost or gave away all the resources I used then.Now I'm having a job wrapping my head around this Arduino because I've forgotten everything.I've started again with a project I found on you tube using the TLC594016-ChannelLED Driver.But I want to add more chips and do more patterns. I managed to figure out the circuit schematic reading the programming text. but still having trouble relearning the rest.Can you folks direct me to some decent books so I can relearn.I like books because I find un-printed PDFs hard to work with and some web sites hard to navigate .

author: brucehoult
author_rank: Super Contributor
timestamp: September 27, 2019, 01:07:53 am
content: This doesn't seem to have anything much to do with C?p.s. Arduino language is officially called "Wiring" and is a carefully-crafted subset of both C++ and Java and sketches are supposed to work in either. (the IDE automatically adds forward function declarations for C++, and a class wrapper for Java)I suspect the Java compatibility of standard code isn't checked all that often these days. And of course user-written code often uses full C++ features.

author: Jwillis
author_rank: Super Contributor
timestamp: September 27, 2019, 05:50:12 am
content: That explains why it looks so strange. I don't know anything about Java. So What I'm looking for is a book specifically for Arduino coding then?

author: westfw
author_rank: Super Contributor
timestamp: September 27, 2019, 09:10:43 am
content: QuoteThis is wrong. The Arduino Language is officially called "the Arduino Language"(1)It is based on the Wiring Language defined as part of Hernando Barragán's Master's Thesis(2)Neither the Arduino Language nor the Wiring Language contain any Java, although they were influenced by "The Processing Language"(3)(which is Java), and have similar abstractions, elimination of build complexities, and rejection of the standard libraries.While they'd apparently like to believe otherwise, the Arduino and Wiring Languages are both C++, though without the C++ STL or even normal C++ libraries (depending on actual chip, actually.) They do some trivial pre-processing to generate forward declarations, and then run the standard avr-gcc/avr-g++ compilers. And they have their own set of "standard" library functions (although avr-libc and/or newlib-nano are present as well.)(4)You can also include plain C/C++ files in your Arduino projects, and the IDE will handle them fine (just with less pre-processing.) (And within the limits of the C++ libraries and features available from the particular compiler.)A good C book is a fine place to start, if you want to understand Arduino code.

author: westfw
author_rank: Super Contributor
timestamp: September 27, 2019, 09:27:42 am
content: QuoteI should add that "a good C++ book" is probably a TERRIBLE place to start, if your goal is to understand Arduino. Most C++ books will immediately plunge you into features and library functions that just aren't there in Arduino (or shouldn't be used, even if they do exist.)Even for C, the starting "Hello World" program won't work because you need to use "Serial.print()" instead of "printf()" (But that's the big one for "beginning C", whereas for C++... I think you'd run into a lot more.

author: westfw
author_rank: Super Contributor
timestamp: September 27, 2019, 10:02:19 am
content: Just posted over in avrfreaks:http://blog.antronics.co.uk/2011/08/08/so-youre-thinking-of-starting-with-c/

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 27, 2019, 03:29:58 pm
content: Just a note, something I kind of keep repeating. C is NOT a subset of C++. The subset of C++ that looks like C still has pretty different rules from C about many things, and I personally think using C++ to learn C is definitely a borked approach.So actually naming the subset Arduino uses "Arduino" was a good idea, so that things don't get mixed up.It's not just the printf() that won't work. Many C constructs are invalid in C++.

author: Jwillis
author_rank: Super Contributor
timestamp: September 27, 2019, 07:23:28 pm
content: Any personal recommendations on the books I should check out?I have nothing right now and theirs just so many choices.

author: MosherIV
author_rank: Super Contributor
timestamp: September 27, 2019, 08:32:00 pm
content: If you want to learn C, the original book"The C programming language"by Kernighan and Ritchie.As others have pointed out, it will not directly work on Arduino. Some tailoring required.Personally, I have not seen ANY Arduino example code that even bearly resembles C++It all looks like some sort of C.

author: westfw
author_rank: Super Contributor
timestamp: September 27, 2019, 10:53:22 pm
content: Quote"Many"? Care to mention a few that are significant, something that would bite a beginning programmer, and not in the "things you shouldn't do anyway" category? I took a look athttps://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2Band the biggest things that jumped out where "C++ won't let you assign (void*) pointers to type pointers without an explicit cast" (which is trivial) and assorted "reserved keywords"...printf() and "cout << stuff" are both capable of working "just fine" in Arduino. It's just that neither stdout nor cout is defined, by default.QuoteMaybe. As things are now, we get questions from "experienced" programmers looking for "more complete definitions of the Arduino Language" (which don't exist, because it's "see a C/C++ manual.) If it was heavily documented as being C++, we'd probably get a similar number of complaints (from similar sources) about exceptions or some STL thing not working.

author: Ampera
author_rank: Super Contributor
timestamp: September 28, 2019, 06:16:31 am
content: Learning C as a means to learn C++ is excellent, learning C++ to learn C is not so much.The book I used to learn C ishttps://www.amazon.com/dp/0321776410/I've found it to explain the basic programming concepts of C in a fairly thorough and easy to understand way, at least enough to use before simply relying on online reference materials.Ardunino programming is also a much different concept, as the standard library is completely different. That's the wonder of C, in that the actual library functions being used can change radically based off what system you're using, but the core syntax and language structures will remain mostly compliant to one of the various C standards. Keep in mind you should have your provided bowl of asterisk cereal for all the damn exceptions that exist.I personally started programming using the Turbo C implementation, as I could more easily jump into the advanced parts of the C language while doing neat things on a DOS platform (like direct screen memory access and messing with BIOS/IVT functions). This may or may not be a good place for you to start too, for which I would suggest the OSDev wiki as a good resource on the various inner mechanisms of the IBM PC architecture.

author: brucehoult
author_rank: Super Contributor
timestamp: September 28, 2019, 06:51:14 am
content: Quote from: MosherIV on September 27, 2019, 08:32:00 pmCode:void loop() {int sensorValue = analogRead(A0);Serial.println(sensorValue);delay(1);}What the heck do you callSerial.println(sensorValue)? That can only be C++ (or Java), not C.

author: Ampera
author_rank: Super Contributor
timestamp: September 28, 2019, 07:44:13 am
content: couldn't you store the pointer to a function in a structure?

author: Nusa
author_rank: Super Contributor
timestamp: September 28, 2019, 07:44:39 am
content: Quote from: MosherIV on September 27, 2019, 08:32:00 pmHere you go, I created this to make you happy. Even used main instead of setup/loop to make it look more normal (the default main() is declaried with a weak attribute, so you can replace it). to make it look more normal. I already had Pin() and Port() classes, so this was trivial.Code:// blink program for digispark attiny85#include "pin.hpp"int main() {init(); // initialize hardware timers so we can use delay()// initialize output pinsPin led0(Port::B, 0, OUTPUT); // utility led on digispark attiny85 version BPin led1(Port::B, 1, OUTPUT); // utility led on digispark attiny85 version A// Blink the builtin led pins. Whichever pin the led is attached to will be visible to the user.while(1) {led0.toggle();led1.toggle();delay(1000);}}

author: Jwillis
author_rank: Super Contributor
timestamp: September 28, 2019, 08:08:39 am
content: Looks like I have some catching up to do.

author: MosherIV
author_rank: Super Contributor
timestamp: September 28, 2019, 10:07:59 am
content: QuoteI would dissagree.I learnt C first. Then I had problems converting from fuctional programming to object orientated.I would recommend learning C++ or Java first to learn OO first.It is easier to comvert from OO to functional (functional is a subset of OO)QuoteAs Ampera said, this can be a call to a function pointer in a struct. The dot operator does not make it C++ !Objects/classes make it C++

author: Nusa
author_rank: Super Contributor
timestamp: September 28, 2019, 10:39:55 am
content: Quote from: Nusa on September 28, 2019, 07:44:39 amQuote from: MosherIV on September 28, 2019, 10:07:59 amSo how do you explain away the scope resolution operator in the declaration of led0 and led1?But I'll give you more since you seem to be in denial:Code:#ifndef pin_hpp#define pin_hpp#include <avr/io.h>#include "port.hpp"class Pin {public:Pin(volatile Port &port, uint8_t pin, uint8_t mode, uint8_t activeLevel = HIGH);void mode(uint8_t mode, uint8_t activeLevel = HIGH);void high();void low();bool active() const;void toggle();private:volatile Port *mPort;uint8_t mPinMask;};inline void Pin::mode(uint8_t mode, uint8_t activeLevel) {((Port *)mPort)->mode(mPinMask, mode, activeLevel);}inline void Pin::high() {((Port *)mPort)->high(mPinMask);}inline void Pin::low() {((Port *)mPort)->low(mPinMask);}inline bool Pin::active() const {return ((Port *)mPort)->active(mPinMask);}inline void Pin::toggle() {((Port *)mPort)->toggle(mPinMask);}#endifCode:#include "pin.hpp"Pin::Pin(volatile Port &port, uint8_t pin, uint8_t mode, uint8_t activeLevel) :mPort(&port),mPinMask(1 << pin){((Port *)mPort)->mode(mPinMask, mode, activeLevel);}Yeah, I left out the documentation blocks, since I didn't want you to get bored before you got to the code.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 28, 2019, 02:50:58 pm
content: Quote from: MosherIV on September 28, 2019, 10:07:59 amYes.This, on the other hand, can't be C:"Pin led0(Port::B, 0, OUTPUT);"so it's immediately obvious that's it's not C code, and that Pin is a C++ object.

author: MosherIV
author_rank: Super Contributor
timestamp: September 28, 2019, 06:33:37 pm
content: Ok, I conceed. The scope operator is definitely C++However, I re-iterate my original statement, most examples of Arduino code is more procedural than object orientated.They are very poor examples to teach people good object orientated coding.I would not recommend using Arduino to learn C++

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 28, 2019, 07:49:43 pm
content: Quote from: MosherIV on September 28, 2019, 06:33:37 pmOh, I agree with that. I'm just saying it's also an even poorer way of learning C.(The libraries themselves are pretty much all written as OO. Granted, basic classes, but still OO. But then yes, most of the example code you can find outside of libraries is poor crap, that is neither really proper C++ nor C.)

author: westfw
author_rank: Super Contributor
timestamp: September 28, 2019, 10:30:45 pm
content: Quoteheh. It depends on what you think C++ should look like.Apparently there is a whole class of C++ programmers who think that C++ programs should look much different than "C with Classes." (Arduino definitely leans toward "C with Classes." I mean, not a single use of STL in the whole thing! And no templates at all! Precious little in the way of operator overloading! Horrors!) (significant amounts of function overloading, though.)Interesting discussion here:https://softwareengineering.stackexchange.com/questions/48401/learning-c-properly-not-c-with-classesI suspect that the people who think like this are not embedded programmers. I find the example "sort" code posted at that link to be ... horrifying, and most "C++ for Microcontrollers" advice starts with "avoid the STL, since it's heavily dependent on dynamic allocation."QuoteAgreed. Although, one of the "problems" learning any new language or paradigm is finding a project that is small enough to understand, and big enough (and scoped) to provide motivation. "Convert THIS segment of the Arduino code to be more in the C++ style" would probably be a great "learning C++" exercise. (Likewise: "modify this C++ library to work better in the Arduino environment.")

author: Ampera
author_rank: Super Contributor
timestamp: September 29, 2019, 03:37:43 am
content: I would dissagree.I learnt C first. Then I had problems converting from fuctional programming to object orientated.I would recommend learning C++ or Java first to learn OO first.It is easier to comvert from OO to functional (functional is a subset of OO)Then perhaps you're getting at it wrong. There's nothing forcing you in C++ to do object oriented much of anything. If anything it's C with some nicer standard libraries and then OOP if you want it.This is how I started C++, and I, for the most part, treat it a lot like C still, just with some nicer quality of life features like maps and simpler memory management that C doesn't have.

author: westfw
author_rank: Super Contributor
timestamp: September 29, 2019, 08:25:25 am
content: "I can write C code in quite a few other languages!"

author: Nusa
author_rank: Super Contributor
timestamp: September 29, 2019, 09:05:37 am
content: I learned and used C before C++, but there wasn't a choice in my case. It was before C++ was created.I also learned the VI editor before the computer mouse was a thing. It's still worth using as well, and the fact that you still don't have to have a mouse to use it is a good thing.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 29, 2019, 02:28:06 pm
content: Quote from: westfw on September 29, 2019, 08:25:25 amOuch, that was a great summary of the current state of things, I think.

author: brucehoult
author_rank: Super Contributor
timestamp: September 29, 2019, 06:57:49 pm
content: Quote from: Nusa on September 29, 2019, 09:05:37 amI learned C and vi together in 1982, on "Eunice" under VMS. The next year we had real Unix on a Zilog System 8000.C was fine. A bit uglier than Pascal or Modula 2, but usable. I bought the first Zortech C++ compiler (for DOS) and ran it on a Mac under VirtualPC. Within a year Apple had C++ as part of MPW (Macintosh Programmer's Workshop) and I switched all my development from C and Pascal to C++.I hated vi right from the start. So crude compared to EDT or EVE on the VAX. Still, that's what Unix systems had, so that's what I learned to use.I don't think I had access to a proper emacs until 1996 or so when I started to use Linux and also acquired a cast-off SPARCStation ELC with Solaris. It was love at first keystrokes and I dropped vi like a hot potato. Ever since then I've used emacs as my primary editor no matter what OS I'm on: Linux, Mac, or Windows.

author: tggzzz
author_rank: Super Contributor
timestamp: September 29, 2019, 07:20:06 pm
content: Quote from: brucehoult on September 29, 2019, 06:57:49 pmSo did I, except it was on that decent operating system from Microsoft: Xenix.Fortunately it also had a rather tasteful editor from a young James Gosling (subsequently of Java fame), Unipress emacs.QuoteAh yes, EDT. The trouble with that was that if you hit "delete word/character", it would delete one of two words/characters depending on what you had been doing some time in the past. If you last moved forwards(backwards) then it deleted the next word forward(backward).Fortunately you could override that idiocy via macros.

author: rstofer
author_rank: Super Contributor
timestamp: October 04, 2019, 04:41:45 pm
content: Quote from: MosherIV on September 27, 2019, 08:32:00 pmEverybody should have that book on their bookshelf, it's a classic! The "ANSI Version" should be on the desk.https://www.amazon.com/Programming-Language-ANSI-Version/dp/8131704947When working with the Arduino, learning C is a secondary topic. The more important part of the project will be interacting with the hardware.Everything that can possibly be done with an Arduino has already been done and the project is out on the Internet, complete with code. Pretty much everything can be built with copy-and-paste.Still, the Arduino code is mostly C and is useful for a learning environment. But, in the end, it's all about interacting with the hardware and library code abounds.

author: MarkF
author_rank: Super Contributor
timestamp: October 05, 2019, 12:06:54 am
content: The book I have is "C++ In Plain English" by Brain Overlandhttps://www.amazon.com/C-Plain-English-Brian-Overland/dp/1558284729/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=1570233556&sr=

author: helius
author_rank: Super Contributor
timestamp: October 05, 2019, 12:47:21 am
content: I'll put in a word for "C Traps and Pitfalls", by Andrew Koenig. It doesn't pretend to be comprehensive, but it covers many of the most common mistakes that are easy to overlook, either by inexperienced programmers or due to shortcomings of the language and operating environments. It's pretty old, so some of the more recent issues around Undefined Behavior are not explored in as much detail as you can find today.

author: jackthomson41
author_rank: Regular Contributor
timestamp: October 10, 2019, 03:58:18 pm
content: For learningEmbedded Systems, the best book is "PIC Microcontroller & Embedded Systems using Assembly & C Language" by Mazidi , there are also his books for Atmel & AVR.

author: SimonR
author_rank: Regular Contributor
timestamp: October 21, 2019, 04:00:03 pm
content: Quote from: brucehoult on September 28, 2019, 06:51:14 amYou're wrong its completely legal C.Quote from: Ampera on September 28, 2019, 07:44:13 amYou're right you canCode:struct {void(*println)(int);} Serial = {printfunction};void loop() {int sensorValue = analogRead(0xA0);Serial.println(sensorValue);delay(1);}

author: helius
author_rank: Super Contributor
timestamp: October 22, 2019, 10:26:16 pm
content: So a function namedprintlnis only capable of takingints? Something is very fishy here.The reason that the code cannot be C is that it uses polymorphism (the printing function is either overloaded or uses template metaprogramming), not the presence of the direct selection operator.

author: Nusa
author_rank: Super Contributor
timestamp: October 22, 2019, 11:40:52 pm
content: Quote from: helius on October 22, 2019, 10:26:16 pmPretend he wrote "foo" instead of "println" then, and that foo is declared as "void foo(int);". Then you won't drag in unstated assumptions about unstated libraries that have nothing to do with the point being demonstrated.

author: brucehoult
author_rank: Super Contributor
timestamp: October 23, 2019, 02:31:54 am
content: Quote from: Nusa on October 22, 2019, 11:40:52 pmHere is "ASCIITable", one of the demo programs included with the Arduino IDE (with absolute beginner comments stripped out for compactness):Code:void setup() {Serial.begin(9600);while (!Serial) {}Serial.println("ASCII Table ~ Character Map");}int thisByte = 33;void loop() {Serial.write(thisByte);Serial.print(", dec: ");Serial.print(thisByte);Serial.print(", hex: ");Serial.print(thisByte, HEX);Serial.print(", oct: ");Serial.print(thisByte, OCT);Serial.print(", bin: ");Serial.println(thisByte, BIN);if (thisByte == '-') {while (true) {continue;}}thisByte++;}Please explain how this could be C, not C++.The context was clearly "the Arduino language", so the Arduino library is hardly an "unstated assumption".

author: Nusa
author_rank: Super Contributor
timestamp: October 23, 2019, 04:31:30 am
content: Except that SimonR's point was that that syntax was possible in C. He'd have to have his own println() function, but it's POSSIBLE.But, now that you've pointed out the context, yes, the Arduino implementation of Serial is certainly a C++ object. The source code is easily found if you really want to see the implementation. There's no mystery at all if one knows enough to read it.When someone talks about the "Arduino Language", if you choose to call it that, it means they're using a C++ compiler with a library of documented functions, implemented both C and C++, built on top of the wiring framework (implemented in C, usually), which in turn is another library with a default main() that calls setup() and loop() and a collection of hardware interface functions.All of which is completely optional. You'll notice in my examples above, I used a main(), and the only wiring functions I called were init() and delay(). I didn't feel the need to spend time implementing delay() myself for an example.

author: westfw
author_rank: Super Contributor
timestamp: October 24, 2019, 04:25:44 am
content: QuoteAs soon as you make it:Code:Serial.println("Sensor Value is");Serial.println(sensorValue);You need C++ (assuming that "sensorValue" isn't a char* pointer or literal string.)

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 24, 2019, 03:41:14 pm
content: Yup. We already went through this with the real "Serial" declaration itself, which could not be C.Of course, if you conveniently omit its declaration (or provide a different one), the rest of the code could look like C, but as westfw just noted, the fact that parameters of different and incompatibles types are passed to the println() function shows it can't be C.Checkmate.Edit: For the most up-to-date C programmers out there, this isn't entirely true. If you're using a C11-compliant compiler, you could have defined println() as a macro, using the new _Generic keyword, expanding to different versions of the println() function depending on the type of its parameters.So...Yes, it could be C11. How many of you know the C11 additions though?And then, the typical declaration of objects (using constructors), which are used ubiquitously in Arduino's libraries, would still not work.In the end, are we going to endlessly arguing that Arduino could be C(11), whereas it's clearly built on C++?

author: bsfeechannel
author_rank: Super Contributor
timestamp: October 24, 2019, 05:43:53 pm
content: Quote from: SiliconWizard on October 24, 2019, 03:41:14 pmYou mean like that?Code:#include "Class.h"int main(){Class obj = Class( 1 );}Code://Class.h#define Class( x ) { (x) }typedef struct {int somerandomvariable;} Class;

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 24, 2019, 07:26:20 pm
content: Ahah, good one. It's relying on the fact that function-like macros are expanded only if invoked with the parentheses. Although it can find some practical uses, I would consider doing this really bad coding practice. But anyway, this wasn't the point I guess.I see this has become a C++ look-alike contest. Or I dunno what.Still, your example doesn't cover the much more usual way of using constructors implicitly, which can be seen in almost all Arduino code: (actually I hadn't seen the explicit way in like ages, except with the 'new' operator)Code:Class obj(1);Seriously guys. Arduino is all built on C++. Deal with it and move on.

author: PlainName
author_rank: Super Contributor
timestamp: October 25, 2019, 02:47:28 pm
content: QuoteCode:#define cppclone(...) cppfake(unused, __VA_ARGS__)QuotePractically, but literally?

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 26, 2019, 12:38:00 am
content: Quote from: dunkemhigh on October 25, 2019, 02:47:28 pmHehe. I see this has sparked some kind of contest. Looks a bit like an obfuscated C contest of some kind, but that's fun.As I said in my "edit" section, there's actually a standard way of doing this properly in C11 with the _Generic keyword. For people interested, please look it up. It can be pretty handy. (Of course, some coding rules you may be subjected to may forbid its use, just like they would generally forbid any fancy preprocessor stuff.)In your example, meant to work with earlier versions of the C standard, there are a couple issues.First, and this is minor (due to a quick typing from your part) is that "unused" is undefined? I get your point, such C functions would require a dummy parameter to make use of variadic parameters, but the passed parameter could be just anything. I would write this instead:Code:#define cppclone(...) cppfake(0, __VA_ARGS__)then the cppfake() function could be declared like so:Code:xxx cppfake(int unused, ...)The main problem with this is that there is no means of passing the types of the expected parameters to the function. To use variadic parameters in C, you need to know the type of each parameter, and their number. The well-known printf() does this through the format parameter. There is no way around it. You can't auto-detect the variadic parameters. So this approach would not be usable.Supposing you find a way (through the preprocessor) to pass the types and number of parameters in a transparent manner (good luck), it would be so horrendous and bug-prone, bypassing all compiler type-checking, potentially doing very nasty stuff to the stack... eek. And being very inefficient, preventing the compiler to do a whole range of optimizations.All this could be fun to discuss in a separate thread, but promoting funky (or borderline desastrous) C constructs in a thread that was meant to be about learning C properly is definitely not a good idea IMO.As one of the users said, "I can write C in almost any language" or something.And now it's evolving into "I can write C++ in almost any language"

author: PlainName
author_rank: Super Contributor
timestamp: October 26, 2019, 07:22:38 am
content: QuoteA case of fingers getting ahead of brain. Your expansion is how it should be, yes.QuoteIndeed! I was aware of that but left it as an exercise for the reader to completeHowever, it should be born in mind that this isn't intended to cover all possible circumstances. Even in C++ you still need to write the handlers before it would compile. Having said that, I can't off-hand think of a suitable handler for the cases where you might pass, say, an int or pointer.QuoteYes. I wouldn't recommend it! In fact, I wouldn't have bothered thinking of it were it not for the checkmate comment

author: westfw
author_rank: Super Contributor
timestamp: October 26, 2019, 08:42:45 am
content: I did consider that in the old days, you could do:Code:int cppfunc(arg)void *arg; /* accept any type of argument, maybe */{PORTB = (int)arg;}int main() {cppfunc(1);cppfunc(PORTB);cppfunc("test");}But it was such a bad idea that I didn't mention it. (you CAN still do this. Don't!)

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 26, 2019, 02:39:23 pm
content: Quote from: legacy on October 26, 2019, 02:27:07 pm

author: legacy
author_rank: Super Contributor
timestamp: October 26, 2019, 02:40:36 pm
content: I am on a piece of code with five level of #define of #define of #define of #define of #define of ...... what? I am lost

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 26, 2019, 02:45:35 pm
content: Quote from: westfw on October 26, 2019, 08:42:45 amIt's 1/ limited to a fixed number of parameters so doesn't fully address the question, 2/ going to do nothing like what the user probably expects, and 3/ the compiler will spit out warnings for parameters with any other type than a pointer, unless you explicitly cast in the function call, which would look ugly and certainly not "transparent" as far as passing any type goes. So first and second calls will yield warnings. And no, ignoring warnings is definitely never a good idea either.For 2/, your third call is just going to issue a write to PORTB with the truncated pointer value of the string, which would certainly do nothing useful here...

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 26, 2019, 02:46:29 pm
content: Quote from: legacy on October 26, 2019, 02:40:36 pmCould you post the chain of 5 #defines so we can have a laugh?

author: legacy
author_rank: Super Contributor
timestamp: October 26, 2019, 05:29:15 pm
content: Quote from: SiliconWizard on October 26, 2019, 02:46:29 pmit's spread among several files. In the top header file, there are defines depending on #ifdef #else whose conditions are grabbed from the usual Kconfig mechanism with a simple #include "config.h" autogenerated according to the the user choices done on the menu config, but when you look at what they define, things go deeper into other includes , which only partially define other things, defined in a sub-layer, and again the same, and again the same, and again the same, like a tree which grows from roots to trunks and leavesGrep says this stuff goes deep from the top to something like 25 files involved, whose low level is practically impossible to be read because there are too many branches and I am not able to follow.In my case, I counted 5 layers of defines, but I am not really sure that I am observing the right code. I mean, what GCC actually compiles.Devs must have lost their head for having made this, or they just want to be evil, masters, and mistresses of evilBecause this is really evil, and dark()

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 26, 2019, 06:22:24 pm
content: Oh well, this kind of monster often grows from a code base 1/ maintained by different people using different styles and 2/ meant to be built with many different configurations on many different platforms. Handling that cleanly is hard.

author: Nusa
author_rank: Super Contributor
timestamp: October 26, 2019, 07:38:09 pm
content: Code:/// moved here for this example. PIND0 is a platform-specific number defined elsewhere#define DIO0_PINPIND0#defineMASK(PIN)(1 << PIN)/// check if pin is an input#define_GET_INPUT(IO)((DIO ## IO ## _DDR & MASK(DIO ## IO ## _PIN)) == 0)/// check if pin is an input wrapper#defineGET_INPUT(IO)_GET_INPUT(IO)Well, here's a real-life case of 5 layers before even getting out of the header file: GET_INPUT(0), _GET_INPUT(0), MASK, DIO0_PIN, PIND0Token pasting (##) can both be magic and confusing. This is a pretty simple case. If you don't understand why the final wrapper is needed, look up "Stringification".(These were swiped from fastio.h in some Repetier printer firmware.)

author: legacy
author_rank: Super Contributor
timestamp: October 26, 2019, 11:21:50 pm
content: Quote from: SiliconWizard on October 26, 2019, 06:22:24 pmYes, it seems so. Different architectures, configurations, vendors, and platforms.I have never given an eye to the layer0, but I need to know exactly where a couple of registers are defined, and which low-level code does handle them.It looked a simple task, a piece of cake ... I am still digging around

author: westfw
author_rank: Super Contributor
timestamp: October 27, 2019, 12:38:57 am
content: QuoteNah. Before varargs was standardized, you could do magic with a pointer to the last argument, or something like that. I've tried to forget...QuoteNope. It's an old-style K&R definition, which essentially gets no type checking at all. The whole program as show compiles with no warnings, even with "-Wall" (avr-gcc)... The function call will put as many arguments as you give it (as "ints", usually) whereever it puts them, and the function will interpret them as it sees fit...QuoteIt wasn't written to be a functional example.Like I said, I'm trying to forget all the ways that we abused C to do what we wanted it to, before better ways were standardized.The other thing you can do is write assembly language subroutines that do anything you want. I think we still use "caller()" that returns the address that the previous function was called from..

author: Nominal Animal
author_rank: Super Contributor
timestamp: October 27, 2019, 12:56:30 am
content: Quote from: westfw on October 27, 2019, 12:38:57 amGCCprovides that as__builtin_extract_return_addr(__builtin_return_address(level)), withlevel==0yielding the return address of the current function, andlevel==1the return address of the previous function. I've also used__builtin_frame_address(level)for the corresponding stack frame.Some of this nonstandard stuff is exceedingly useful in debugging and such; probably why they still exist.

author: legacy
author_rank: Super Contributor
timestamp: October 27, 2019, 04:40:30 pm
content: I see there are #define __weak defining a prefix for functions.What is this ___weak attribute used for?

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 27, 2019, 05:27:08 pm
content: Quote from: legacy on October 27, 2019, 04:40:30 pmThis is a GCC attribute, non-standard, but can be pretty handy (although also slippery).This allows to define a function that can be overriden without causing a symbol clash. Meaning, if a function is defined "weak", you can further define a function with the same identifier, in which case the latter will be used.One way it can be useful in embedded dev for instance, is that you can provide a weak definition for all interrupt/exception handlers, with a default behavior. Then you can easily override any of them.https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes

author: Nominal Animal
author_rank: Super Contributor
timestamp: October 27, 2019, 09:50:05 pm
content: Yep, what SiliconWizard wrote.Furthermore, it exposes theweak symbolfacility ELF files provide; it does not actually generate different code, just marks that symbol weak/overridable in the symbol table. So, it has everything to do with ELF object files and linking, and nothing to do with C per se.

author: MarkL
author_rank: Unknown
timestamp: October 28, 2019, 12:12:34 am
content: Quote from: SiliconWizard on October 24, 2019, 03:41:14 pmI don't the know intricacies of C11 additions, but GCC has supported a similar thing called __builtin_types_compatible_p(TYPE1, TYPE2) which tests whether TYPE1 is compatible with TYPE2. A series of if's could be built up to handle multiple types.Apparently _Generic is in gcc as of 4.9, but the functionality isn't new.

author: pwlps
author_rank: Frequent Contributor
timestamp: December 30, 2019, 06:55:10 pm
content: Quote from: helius on October 05, 2019, 12:47:21 amMy favorite second book on C is this one:http://progforperf.github.io/Expert_C_Programming.pdf