If you are going to use C, then at least know what it's doing!
If you're going to learn C, you better learn assembly, so you know what the C is doing.
If you're going to learn assembly, you better learn CPU architecture, so you know what the assembly is doing.
If you're going to learn CPU architecture, you better learn digital logic, so you know what the adders and multiplexers are doing.
If you're going to learn digital logic, you better learn solid-state physics...
I mean, it's always useful to know what's happening under the hood, but it's not always realistic to expect that to happen. I don't think the average C programmer need to know assembly any more than the average Ruby programmer needs to know C.
I really don't have an issue with someone being a dev in Ruby who doesn't understand pointers or how if/else statements can be constructed from jmp primatives. But if you're on the road to expertise I don't think you can remain ignorant of these.
And, FWIW, when I did CompSci back in the '80s, the first courses/tutorials involved building half-adders and flip-flops from NAND gates and wires on a plug-board.
You don't _need_ to know that sort of stuff, especially not in any level of detail, to build another CRUD webapp - and with luck a hugely successful business on the back of your CRUD app - but I think there's a personality trait that comes along with all the other stuff that makes some people "hackers" which characterises many of us as insanely curious. Many of us don't want to treat the latest Ruby ORM features or Node.js's async callbacks as a "black box", we want to "know how it works" - sometimes out of pure curiosity, and sometimes because it fails _hard_ and we can't work out why without understanding what it's doing "under the hood".
Sure, you can generally get by without low level knowledge, but it's nice knowing why certain design decisions were made. And as far as C goes, I think it's extremely useful to be familiar with how it translates to assembly, at least in general. It is knowledge that you will use regularly if you're programming in C in any significant capacity.
For example, reasoning about ABIs is something you'll have to do if you ever write a stable library interface. Reasoning about ABIs requires you to know the asm-level calling convention for the platform you're coding on.
A master C programmer knows assembly well, a good chunk about CPU architecture, some things about digital logic and superficially about the physics.
I disagree. Given that C exposes you to some hardware details that are abstracted when developing in some higher level language such as Ruby, for instance having to deal with overflow on signed/unsigned types and register variables (I know that compilers will mostly ignore that, but it's still a language feature).
The average Ruby programmer, on it's turn, can perfectly live without knowing C programming. A more accurate analogy would be to a Ruby programmer to know about the language implementation being using (MRI, JRuby, Rubinius, etc.)
How far you go down the rabbit hole depends of how much of this supporting knowledge you need to work at the level you work. Given the layers of software abstraction that exist in systems these days is it really necessary for a programmer to have a detailed knowledge of how a transistor works? Not at all. Your much better spending the time building a mental model of how your VM or OS layer is working and going to interpret the code you write. Or even looking up and understanding the layers that will use what you write - like users and customers (now there is a real challenge!) For sure take an interest in all things, but as you go down the layers your thinking can be increasingly abstract and like any model, plain wrong and it won't really matter.
(I'm a C programmer, I don't look at assembly that often at all, but it's certainly helpful to be able to do so and my knowledge of the x86 ISA, calling conventions, etc has informed many decisions I've made in the past, especially re: performance)
I think it's useful to have a basic understanding of assembly so that you can debug better, or understand why some behaviors are undefined. I think that only takes a basic understanding of assembly though.
If you want to be an expert at assembly, you probably want to go deeper, but most people don't have that goal.
When things go wrong it is useful to have knowledge of n-steps deep to immediately cut through ton of output and nail down a few places things seem to work not as expected.
-Carl Sagan
$ CFLAGS="-g -O0" make simple
cc -g -O0 simple.c -o simple
$
This is so handy. I never knew that you could call make without writing a default Makefile. Thanks! make CFLAGS="-g -O0" simple
(This also works with many other build tools like CMake or configure scripts generated by autoconf.)If you're curious which rules exist by default, try running:
make -p
(This produces a lot of output; a bit much to study in detail, but still useful to scan just to get an idea of what default rules exist.) echo 'void main() { printf("omg\n"); }' > simple.c
echo 'CFLAGS=-g' > Makefile
make simple
./simple
(yes I know that is not valid C but it serves this example and compiles fine :-)redo makes everything much simpler, more consistent, more dependable, and more robust. e.g all files are atomically replaced; dependencies are checked by a crypto hash of the content; dependency setup is sane; and it's all faster than make.
You can also use `objdump` from binutils
* Knowing what the machine is doing is useful and important, especially while debugging. I think every really good C coder I know has been comfortable with assembly at least on some platform.
But…
* C is not a fancy macro assembler. C's behavior drives an abstract machine, and any machine code that achieves the same output assuming that all the C behavior is defined is equally valid. The believe that compiler is just transliterating your code to ASM is responsible for many serious bugs. C Compilers haven't been like that for 20 years (or more). E.g. aliasing rule violations. The fact that it isn't is utterly essential for performance, especially as things like good SIMD use become more critical for performance.
Even when the compiler is mostly transliterating the expectations from the simplified mental machine model can be misleading, e.g. alignment requirements on load on some architectures.
One good combination would be Assembly + C + Python for instance. Assembly helps understanding C and C helps with understanding Python.
In my CIS240 class (currently enrolled) we learn computers from the ground up and eventually learn C. First we do binary arithmetic by hand to get a feel for it, then we design basic circuits (and some complicated) that can perform the basic computer instructions (ADD. MULT, SHIFT, AND, XOR, etc.) then we keep building up off of these basics until we are finally writing C, at which point we will (hopefully) have a good grasp at what is going on and appreciate our programming language of choice a whole lot more.
In regards to the original post, I'm not sure I would be putting C with assembly or learn one over or for the other. They both have their uses and reasons for knowing. Forcing yourself to learn one before the other does not seem like a logical way to go. I think it's best to start with what makes the most sense for your end goal and / or you are most interested and motivated to begin and get most deeply into.