Real talk, I feel like C is more a scripting than compiled language.
Not only because it has week types. Where do I start...
So what defines a scripting language? It's interpreted rather than
compiled but often their also come with dynamic types and garbage
collector. The idea is to make them noob friendly to get the job done
without thinking about lower level concepts. This is exactly how I
feel when programming in C after applying few concepts.
1. Compiled vs interpreted. The convenience here is that you only run
the program. No need to setup the compilation or wait for it.
Most of my C programs are build from single compilation unit using
single header libraries or nothing at all. This not only makes the
compilation setup trivial with just "$ gcc main.c" but also blazing
fast. With that I have single command to build and run program and
in practice it feels like I am only running it.
So for me there is no compilation. Unless there are compile time
errors. But those are actually lesser evil than runtime errors and
I want to have them.
2. Dynamic types. In scripting language you just assign random stuff
to variables and it all works. MAGIC! Except for the confusing
part when you like to use variables of different types together.
Depending on language this is handled differently but it's usually
the most confusing part in dynamic types.
My realization with C was that everything is a number. I know that
everyone is aware of that when talking about computers, binary and
stuff. But you rarely see a source code that uses only numbers.
Even in C we like to have more abstract concepts like String, Null,
Boolean, Date, File etc. for primitive types.
Observation here is that the less types you use the more dynamic C
becomes. I'm usually fine with int, char and pointers. Often it's
necessary to use float and FILE. Rarely more. But mostly all vars
are just integers as those can be a file descriptor, error, enum,
counter, boolean, flag, date, socket etc. And when all variables
are of the same type then one of them have a type. It almost feels
like writing "var" from JS when I write "int" in C as it doesn't
matter that much what will be the value.
OFC you can't escape types entirely. Also by not having specific
well defined types you can't tell what kind of information is held
by the integer. But my thinking is that enums, errors, dates, file
descriptors etc. are all a lie, there are only numbers. Thinking
of them as specific types will make your program more complicated,
but seeing them as numbers will open doors to simpler code.
You can still enforce arbitrary rules to your variables, like max
value or allowed value, with assertions. This will produce runtime
error which makes C program fell even more like a script. Not
necessarily a good thing in this case but assertions gives greater
control over expected values than types. I found out that the best
place to use them is right at the beginning of function to validate
all assumptions of function arguments.
BTW you can omit return type in function declaration and it will be
an integer by default. Try to write a program that way and it will
have script vibe.
3. Garbage collector. This one is all about not caring about memory
management. Is bizarre as essentially programming is only about
getting data from one place and placing it in another place which
is memory management.
Anyway, when writing programs in C that don't run continuously but
rather execute single task and then terminate you can safely forget
about freeing the heap memory. Even better, you can avoid calling
malloc() most of the time as usually you can predict or assume
sizes of things easily. At least the maximum sizes.
Operating System will free program memory once terminated and it
will probably do it better than you (o_o ).
But what to do when you need a lot of dynamically heap allocated
memory? Well then you can just call malloc() once at program start
asking for big chunk of memory, like 1 GB. OS will not take away
all of 1 GB from your system resources. It will only take the
amount that you use. And again you don't have to free it as you
will use this bi chunk for entire lifetime of your program.
Obviously there are exceptions to those two cases but usually this
is all you have to do and there is no memory management anymore.
In summary, C will feel like a scripting language when you use:
1. Single compilation unit for easy and fast builds.
2. Less types, mostly integers, chars and pointers.
3. Allocation on heap sparingly without free() or not at all.