Author Topic: General C programming question  (Read 8318 times)

0 Members and 1 Guest are viewing this topic.

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: General C programming question
« Reply #25 on: July 20, 2018, 02:45:08 pm »
I see a lot of people here talk about compile/build time, which seems surprising. This is an embedded forum, so the builds we're talking about aren't that big--it's not like you have to compile the linux kernel each time. Is the difference between a 30 second build and a 2-minute build really important? Seems like the impatience of youth, IMO.

The difference between 2-minutes and less than a second is huge. It allows you to compile frequently, which changes your workflow and lets you be substantially more productive.

If you need to wait 2 minutes for every compile, it forces you to write more code between the compiles, and if you've got a problem, you now have to wonder which of the changes caused the bad behaviour, perhaps unroll some of your changes back, start a debugger. This all takes time and makes your work tedious. You get tired faster.

If the compile time is less than a second, you can do a single change, compile and check the result immediately. If something bad happens, you know the problem was at your last change. Of course, in the embedded, there's a programming delay and then there could be a delay with starting the test, but I always try to make such delays as short as possible.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4036
  • Country: nz
Re: General C programming question
« Reply #26 on: July 20, 2018, 03:19:01 pm »
[Pascal] also much easier for the compiler, so your compiles get faster (old Delphi compiler can compile 300K lines in less than a second).
I see a lot of people here talk about compile/build time, which seems surprising. This is an embedded forum, so the builds we're talking about aren't that big--it's not like you have to compile the linux kernel each time. Is the difference between a 30 second build and a 2-minute build really important? Seems like the impatience of youth, IMO.

Sure, when you're chasing that bug at 2am and on your 2nd Red Bull, that extra 90 seconds feels like an hour.  :o

I just read on reddit (I think) about a new programming language called Lily. I downloaded it off github and build it. It took almost exactly 1 second on my i7 NUC. I see in the makefile it's using -O2.

There are 26 C source files, totalling 23560 lines of code. Once preprocessed that expands to 90905 lines.

That's not quite the speed claimed for Delphi, but it's still bigger than most embedded projects -- the executable created has 230453 bytes in the text section.

I wasn't tooooo bored waiting for it to compile.
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: General C programming question
« Reply #27 on: July 20, 2018, 03:26:21 pm »
Does nm(1) show you that unused functions are absent? 
Dunno, I never actually searched for unused functions.

Quote
With MCU makers funding work on the Gnu dev tools it would make sense to do that.  What actually happens when you pass those flags may be target dependent.
Valid point. But GCC for Cortex-M covers the majority of my projects (i.e., 100%  :)), so I haven't had to worry about portability too much. I'm interested in trying out Clang/LLVM for Cortex-M one of these days, but I think both toolchains use the same approach to dead code elimination.
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: General C programming question
« Reply #28 on: July 20, 2018, 03:47:09 pm »
The difference between 2-minutes and less than a second is huge. It allows you to compile frequently, which changes your workflow and lets you be substantially more productive.
Well, lets chalk that up to differences in development style. Most of the times I compile something, it's to make sure its syntactically correct, or that the linker produces a binary--not to actually run or flash the code.

Quote
If you need to wait 2 minutes for every compile, it forces you to write more code between the compiles, and if you've got a problem, you now have to wonder which of the changes caused the bad behaviour, perhaps unroll some of your changes back, start a debugger. This all takes time and makes your work tedious. You get tired faster.
Nobody is forcing you to write more code.  I had to wait 45-minutes for a build back in the 80s, so I'd go into the machine room and practice juggling.  :-DD

https://xkcd.com/303/

Quote
If the compile time is less than a second, you can do a single change, compile and check the result immediately. If something bad happens, you know the problem was at your last change. Of course, in the embedded, there's a programming delay and then there could be a delay with starting the test, but I always try to make such delays as short as possible.
Lightning fast builds seem to be possible with IDEs and/or tiny programs, but neither of those apply to the projects I end up working on.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: General C programming question
« Reply #29 on: July 20, 2018, 04:06:08 pm »
Nobody is forcing you to write more code.  I had to wait 45-minutes for a build back in the 80s, so I'd go into the machine room and practice juggling.  :-DD

How about you leave your deck to be run overnight and come back next day for the printout?

Lightning fast builds seem to be possible with IDEs and/or tiny programs, but neither of those apply to the projects I end up working on.

It would if you had fast Delphi-style compilers.

 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: General C programming question
« Reply #30 on: July 20, 2018, 04:19:17 pm »
How about you leave your deck to be run overnight and come back next day for the printout?
Zing!  :box:

Quote
Quote
Lightning fast builds seem to be possible with IDEs and/or tiny programs, but neither of those apply to the projects I end up working on.

It would if you had fast Delphi-style compilers.
Can I run my awk scripts from within Delphi?
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: General C programming question
« Reply #31 on: July 20, 2018, 04:52:42 pm »
Can I run my awk scripts from within Delphi?

I'm not talking about Delphi (as IDE), just the underlying compiler.

BTW, I still use the command-line version of the Delphi compiler. I often write simple programs to generate code (tables, C code, or even Pascal code), which I use in the places where you use your awk scripts I guess. It is my "go to" compiler when I need to write something for my own use.

 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 6460
  • Country: nl
Re: General C programming question
« Reply #32 on: July 20, 2018, 10:29:40 pm »
Nobody is forcing you to write more code.  I had to wait 45-minutes for a build back in the 80s, so I'd go into the machine room and practice juggling.  :-DD
I wish it was the 80s, if I do a full build it will be scheduled at night since sometimes it takes two hours to complete  :(
Luckily you don't need full builds often, just compiling your files or even the entire subcomponent takes seconds.
 

Online westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: General C programming question
« Reply #33 on: July 20, 2018, 10:58:11 pm »
>
Quote
Does nm(1) show you that unused functions are absent? 
yes, of course.   We're not just making this up, you know.Arduino in particular is heavily reliant on this linker/compiler feature get get rid of most of the class methods that C++ programmers love to add to their source code, which are hardly ever all used in the same sketch.
For an obvious example, compile a simple "Serial.print("Hello World");" sketch and note that the .elf file ends up with only:
WWHackintosh<10025> avr-nm -SC sketch_jul20a.ino.elf | grep Print
00000114 00000006 t Print::availableForWrite()
00000112 00000002 t Print::flush()
000000be 00000054 t Print::write(unsigned char const*, unsigned int)


In spite of Print.cpp.o being much more ... bloated:

WWHackintosh<10026> avr-nm -SC ../arduino_build_474806/core/Print.cpp.o | grep print
00000000 000001b6 T Print::printFloat(double, unsigned char)
00000000 00000092 T Print::printNumber(unsigned long, unsigned char)
00000000 00000048 T Print::print(__FlashStringHelper const*)
00000000 00000004 T Print::print(char const*)
00000000 0000001c T Print::print(String const&)
00000000 00000014 T Print::print(Printable const&)
00000000 0000000e T Print::print(char)
00000000 00000004 T Print::print(double, int)
00000000 0000000e T Print::print(unsigned char, int)
00000000 0000000e T Print::print(int, int)
00000000 0000000c T Print::print(unsigned int, int)
00000000 00000090 T Print::print(long, int)
00000000 0000001a T Print::print(unsigned long, int)
00000000 00000024 T Print::println(__FlashStringHelper const*)
00000000 00000024 T Print::println(char const*)
00000000 00000024 T Print::println(String const&)
00000000 00000024 T Print::println(Printable const&)
00000000 00000024 T Print::println(char)
00000000 00000024 T Print::println(double, int)
00000000 00000024 T Print::println(unsigned  char, int)
00000000 00000024 T Print::println(int, int)
00000000 00000024 T Print::println(unsigned int, int)
00000000 00000024 T Print::println(long, int)
00000000 00000024 T Print::println(unsigned long, int)
00000000 00000008 T Print::println()



>
Quote
What actually happens when you pass those flags may be target dependent.
No, it's pretty platform-independent.  And sort of obvious in retrospect - it just tells the compiler to generate object files in a way that makes it possible for the linker to treat individual functions as if they had come from individual .o files.   Whether existing libraries are compiled with the necessary compiler switches is another question.  AFAIK, while it's "obviously easy" for a compiler to put each function in a separate "section" (-ffunction-sections) during the compile phase, it's not possible to split up an existing .o file...

Although my impression is that outside of the embedded arena, most programs simply map in huge .dll run-time libraries with no attempt to optimize which functions are actually present.  "If it's not used, the pager will never read it in.  Maybe.  Who cares - 8GB of RAM and 64bits worth of address space!"
 
The following users thanked this post: Araho

Offline rhb

  • Super Contributor
  • ***
  • Posts: 3483
  • Country: us
Re: General C programming question
« Reply #34 on: July 21, 2018, 12:15:11 am »
Very nice to know. Thank you.   I'm glad to see that some progress is being made. Most of the time I feel as if software engineering is going backwards.

I just wish the options would be used more.  I can't run Hipster on a 2 GB dual core Atom machine because Firefox consumes all the memory to the point you can't enter text as I am doing now.  It's like being at the end of a 300 baud dialup.
 

Online westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: General C programming question
« Reply #35 on: July 21, 2018, 01:10:26 am »
Quote
I just wish the options would be used more.  I can't run Hipster on a 2 GB dual core Atom machine because Firefox consumes all the memory
Desktop programs are convinced that the NEED EVERY FUNCTION, and I don't think you can blame their bloat on including unused library functions.  (I'd be willing to be proven wrong, though.)
Also: VM - if firefox has vast number of unused functions, they probably wouldn't get paged in, and wouldn't cause the usage you're seeing.
 

Offline JanJansen

  • Frequent Contributor
  • **
  • Posts: 380
  • Country: nl
Re: General C programming question
« Reply #36 on: July 22, 2018, 12:40:07 pm »
Here is my "expert advice" :

Why would you type a function prototype if you dont need to type it.
So yes i organize my code that i would not need any function prototype if possible.

I only place function prototypes in main.h when they need to be called by another file.
If i need function prototypes that will only be used in main.c then i place the function prototype in main.c to make things more clear.

Main.h includes all other files from your project, and all headers include main.h, while the .c files only include theyr own header to start with.
Sometimes there are problems, i,m not sure how or what, in general it works like this with me.
aliexpress parachute
 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 6460
  • Country: nl
Re: General C programming question
« Reply #37 on: July 22, 2018, 03:22:34 pm »
My expert advice never ever use a main.h file, it should not exist.
Why?
Because a header file per definition is included by another file, thereby implicitly states that the belonging *.c file is a resource for another file to use.
Main.c is the highest in the hyrarchy it must and will never be included by another file, therefore it shall not have a header file and it should also not contain public functions needed by other files.
 

Online ajb

  • Super Contributor
  • ***
  • Posts: 2604
  • Country: us
Re: General C programming question
« Reply #38 on: July 22, 2018, 05:59:46 pm »
Why would you type a function prototype if you dont need to type it.
So yes i organize my code that i would not need any function prototype if possible.

Function prototypes are inherently a violation of the DRY* principle which means they're kind of a bummer to write, but trying to structure a program to avoid them is kind of a bigger bummer.  Once you've defined a function, just copy and paste the first line of the definition to the top of the file and never worry about the order of your definitions again.  You also get a nice table of contents at the top of the file this way.  Then if you decide later on to make that function public, you can copy the prototype to an .h file. 

* Don't Repeat Yourself
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: General C programming question
« Reply #39 on: July 22, 2018, 06:42:54 pm »
Once you've defined a function, just copy and paste the first line of the definition to the top of the file and never worry about the order of your definitions again.

My function declarations may change as I go. If I have it in two different places, I need to synchronize them - and that's a lot of worrying :) Absolutely no way I would write redundant declarations unless I have to.
 
The following users thanked this post: GeorgeOfTheJungle, JanJansen

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 6460
  • Country: nl
Re: General C programming question
« Reply #40 on: July 22, 2018, 09:31:50 pm »
Once you've defined a function, just copy and paste the first line of the definition to the top of the file and never worry about the order of your definitions again.
Although this works (compiles) it is actually better IMO to not use the variable names in the declaration.
The declaration is what the compiler needs and only has to contain the function name and data types for the parameters.
The definition (implementation) is what the linker needs so only there the variable names are relevant.
It is then also easier to change you're variable names.

My function declarations may change as I go. If I have it in two different places, I need to synchronize them - and that's a lot of worrying :) Absolutely no way I would write redundant declarations unless I have to.
Let the compiler worry for you , it will throw an error on any significant difference between declaration and implementation. That is you changed data types eg from uint16 to uint32 for instance, but not if you changed the variablename of any parameter if you follow the above advice.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: General C programming question
« Reply #41 on: July 22, 2018, 10:24:20 pm »
My function declarations may change as I go. If I have it in two different places, I need to synchronize them - and that's a lot of worrying :) Absolutely no way I would write redundant declarations unless I have to.
Let the compiler worry for you , it will throw an error on any significant difference between declaration and implementation. That is you changed data types eg from uint16 to uint32 for instance, but not if you changed the variablename of any parameter if you follow the above advice.

Compiler finding the differences, me fixing them - looks like useless work to me.
 

Offline sleemanj

  • Super Contributor
  • ***
  • Posts: 3024
  • Country: nz
  • Professional tightwad.
    • The electronics hobby components I sell.
Re: General C programming question
« Reply #42 on: July 22, 2018, 10:28:20 pm »
Although this works (compiles) it is actually better IMO to not use the variable names in the declaration.

The declaration forms part of your headers (be they in a .h file, or at the top of your .c), which can be considered documentation,

  int foo(char, char, char);

is not helpful to the developer who wants to use function foo.  If that is all that is in the header file/section, then they have to then dig through to find the implementation of this function just so they can see which order the operands are in. 

Not naming your parameters in a declaration is lazy, it costs time, and has the potential to introduce errors - subtle ones caused by a developer using foo switching operands which just happened to work out the same way in their initial testing.

If you are using declarations, make them verbose and proper, don't take short cuts, not using declarations is preferable to using lazy ones.


~~~
EEVBlog Members - get yourself 10% discount off all my electronic components for sale just use the Buy Direct links and use Coupon Code "eevblog" during checkout.  Shipping from New Zealand, international orders welcome :-)
 
The following users thanked this post: sokoloff

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 6460
  • Country: nl
Re: General C programming question
« Reply #43 on: July 23, 2018, 07:05:39 am »
Agree, I am just saying it is not necessary not that from a readability point of view is recommendable.

Still if you document your function with lets say doxygen you can read the documentation for the function.
Also you can use good comments you need to go to the definition anyway.
 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 6460
  • Country: nl
Re: General C programming question
« Reply #44 on: July 23, 2018, 07:07:02 am »
Compiler finding the differences, me fixing them - looks like useless work to me.
From that point almost 3/4 a good SW programmer does is "useless work" untill someone else needs to take over to read or modify the code  ;)
 
The following users thanked this post: ajb

Offline JanJansen

  • Frequent Contributor
  • **
  • Posts: 380
  • Country: nl
Re: General C programming question
« Reply #45 on: July 23, 2018, 02:02:03 pm »
My expert advice never ever use a main.h file, it should not exist.
Why?
Because a header file per definition is included by another file, thereby implicitly states that the belonging *.c file is a resource for another file to use.
Main.c is the highest in the hyrarchy it must and will never be included by another file, therefore it shall not have a header file and it should also not contain public functions needed by other files.

The main.h you could rename to allfiles.h, it includes all files, so you only have to include main.h in your other headers.
*i am repeating myself, lets say clarify, now i stop repeating this, i hope you see the logic now.

+ i had made a game engine with many many files, you are suggesting that main.c only has a main function in it,
i learned from that mistake, i now have a few files for my latest game engine, less then 100, placing many things in 1 file, else i would have more then 100 files, i think the compiling takes also longer, + you cant have all files open at once in screen.
I cant perfectly describe how good this simple change is.
aliexpress parachute
 

Offline Kjelt

  • Super Contributor
  • ***
  • Posts: 6460
  • Country: nl
Re: General C programming question
« Reply #46 on: July 23, 2018, 02:06:59 pm »
A compile will usually take less time when multiple files unless they all are referencing each other.
Only modified files will be recompiled at build time unless you perform a clean build ofcourse.

Sorry but I have to ask what is your experience as profesionall software engineer ?
« Last Edit: July 23, 2018, 02:14:01 pm by Kjelt »
 

Offline JanJansen

  • Frequent Contributor
  • **
  • Posts: 380
  • Country: nl
Re: General C programming question
« Reply #47 on: July 23, 2018, 02:13:54 pm »
Once you've defined a function, just copy and paste the first line of the definition to the top of the file and never worry about the order of your definitions again.

My function declarations may change as I go. If I have it in two different places, I need to synchronize them - and that's a lot of worrying :) Absolutely no way I would write redundant declarations unless I have to.

Suppose you need a function prototype i have a small tip for you when things get hectic : use a construction parameter struct to pass instead of many arguments.
aliexpress parachute
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: General C programming question
« Reply #48 on: July 23, 2018, 02:53:42 pm »
Suppose you need a function prototype i have a small tip for you when things get hectic : use a construction parameter struct to pass instead of many arguments.

This makes things more complicated when you call a function. You either need to create a structure to pass to the function, or you need to use compound literals.

You can use a macro which contains the whole declaration, but for some reason it doesn't sit well with me.
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: General C programming question
« Reply #49 on: July 23, 2018, 03:17:24 pm »
If when you open a main.c, main() isn't the last thing at the bottom, that's a bad smell, means something fishy is going on.
The further a society drifts from truth, the more it will hate those who speak it.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf