
Understanding C by learning assembly - davidbalbert
https://www.hackerschool.com/blog/7-understanding-c-by-learning-assembly
======
nullc
Mixed feelings here:

* 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.

------
dude_abides

      $ 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!

~~~
sltkr
Note that this uses the Bourne shell feature of modifying the environment of
the make process by prefixing the command with an environmental variable
assignment. The more portable/shell-agnostic version is to pass such
assignments as arguments to make instead, i.e:

    
    
        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.)

~~~
toughluck
"make -p"

Of course this only applies to GNU make.

~~~
simias
Works on FreeBSD's make as well (with a sligthly different output format).

------
erichocean
A thousand times yes.

If you are going to use C, then at least know what it's doing!

~~~
prophetjohn
Can't this reasoning be applied recursively?

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.

~~~
Homunculiheaded
I think someone who claims expertise in 'software' should understand the
process until it stops being software, which is architecture. Honestly I think
the 'average' Ruby programmer ('average' reflecting their understanding of
ruby) who really claims to understand software should know C and ASM.

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.

~~~
tsahyt
I think a good C programmer should have a grasp on how assembly works. This
can come in incredibly handy for debugging weird errors. Yes there are bugs
that are weird enough to only become evident in assembly code. An
understanding of assembly also makes memory management and pointers in C so
much more understandable. Also, assembly reveals quite a bit about
performance: Less instructions == faster code. Then there are some platform-
specific things that aren't available[1] from C (at least the standard
library) like SSE or MMX instructions. These can give you a _big_ speedup
(think of it as "micro-parallelization") if used correctly. Some things in
glibc (mainly in string.h) are implemented using them, but as far as I know
the standard library doesn't provide an interface to them and the compiler
usually isn't smart enough to use them when appropriate. So if you're trying
to squeeze the last bit of performance out of a program you'll often have no
choice but implementing a bit of assembly code as well.

Concerning architecture: One might argue it's not neccessary but I think a
_good_ C programmer should at least have scratched the surface here. No deep
understanding, but a bit of an overview of what's going on. That is - I think
- the point where it no longer concerns you as a programmer. Architecture and
Assembly really go hand in hand, since every architecture comes with its own
assembly code (yes I know, some assemblers are abstracting that away
sometimes). That is why some things work faster on, say SPARC than on x86. It
also helps understand the limits we're given and what "64 bit" _really_ means.

Understanding architecture doesn't really help writing better C code, but it
explains things the compiler does, since in a pipelined architecture, the
compiler will arrange assembly instructions, so there are as little stalls as
possible and therefore gaining performance.

[1] I might be wrong on that though. Please correct me if I am.

------
niggler
You can run gcc with the -S flag, which will dump the assembler output (so you
dont have to go through gdb)

You can also use `objdump` from binutils

~~~
tsahyt
gcc -S is usually preferable, since you don't get all the code
produced/included by the linker to get the thing running.

~~~
dbaupp
And using gcc -S allows you to get a few extra annotations (variable names
etc.) using the -fverbose-asm flag.

------
ginko
I sometimes think that an ideal approach to learn programming might be to
learn it on several abstraction levels at once to see how things interact.

One good combination would be Assembly + C + Python for instance. Assembly
helps understanding C and C helps with understanding Python.

------
habosa
I'm not sure how long this has been the case, but this is how C is taught at
my school (Penn) and I'm sure many others.

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.

------
b3b0p
Assembly was always daunting to me. Then I took Computer Systems at the
University. It ended up being seriously fun. The way it made me think and try
to solve problems were engaging and different it seemed. It required a new way
of thinking and made me think about things I never thought about. Although we
only wrote smaller programs for the class, I found them fun and I still
remember the class nearly 10 years later.

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.

------
pacman128
I used to teach Assembly and I spend a lot of time talking about how it
connected with C since assembly is almost always used in conjunction with C. I
have a free text on the web that was used in the class. It only covers 32-bit
x86 since that's all there was back then. <http://www.drpaulcarter.com/pcasm>

------
novalis
Fascinating, reading it made me remember how fun it was to use Softice.

~~~
zwieback
I loved SoftICE, especially the NMI button that you could slide into an ISA
slot.

~~~
novalis
I think I lost track because of the lack of support after Windows XP. But I
did read (on some dedicated forum) someone had it running with Vista and
onwards, just never been able to find it. I think there was a symbol table no
show release and a company buy out. Do you use something with Ring Zero now,
to substitute it?

~~~
zwieback
No, I moved on to other things, now I'm doing mostly embedded with external
debug probes for debugging.

------
jstrayer
It's been more than a decade since I've worked in C, but don't C compilers
have an option to emit assembly directly?

------
naavinm
Hmm, interesting..

