— 由 @Niefan Du 翻译
我们这门课以Scratch开始,然后我们学习了C.
回想一下我们在C语言中写源代码,但是我们需要在我们的计算机运行它前,把它编译成二进制的机器代码.
clang是我们我们学着用的那个编译器,而make是一个实用程序,帮助我们在无需手动指示所有的选项的同时,运行clang.#include <cs50.h>,然后使用clang而不是make,我们则还需要添加一个标志(flag):clang hello.c -l cs50.标志l链接(link)了cs50文件,而它早已被安装在了CS50沙盒中.“编译”源代码成机器代码的过程其实是由这几个更小的步骤构成的:
预处理涉及到在其它任何事情的开始之前,先查看以#开头,像#include这样的代码行.例如,#include <cs50.h> 会告诉clang去先查找头文件,因为它里面包含着我们想要包含在我们程序中的内容.然后,clang会将这些头文件里的内容替换到我们文件中来:
...
string get_string(string prompt);
int printf(const char *format, ...);
...
int main(void)
{
    string name = get_string("Name: ");
    printf("hello, %s\\n", name);
}
编译接受我们的C语言源代码,把它转化为汇编代码(assembly code),看起来就像下面这些一样:
...
main:                 # @main
    .cfi_startproc
# BB#0:
    pushq %rbp
.Ltmp0:
    .cfi_def_cfa_offset 16
.Ltmp1:
    .cfi_offset %rbp, -16
    movq %rsp, %rbp
.Ltmp2:
    .cfi_def_cfa_register %rbp
    subq $16, %rsp
    xorl %eax, %eax
    movl %eax, %edi
    movabsq $.L.str, %rsi
    movb $0, %al
    callq get_string
    movabsq $.L.str.1, %rdi
    movq %rax, -8(%rbp)
    movq -8(%rbp), %rsi
    movb $0, %al
    callq printf
    ...
下一步是取汇编代码,通过汇编将其转化成二进制的指令.
现在,最后一步是链接,将那些我们链接的,如同cs50.c的库文件,以二进制的形式包含在我们的程序中.
假如说我们写了一个程序叫buggy0:
int main(void)
{
    printf("hello, world\\n")
}
make这个程序,我们并没有包括任何的头文件.help50 make buggy0,它最终会告诉我们,我们应该#include <stdio.h>,因为它包括了printf.让我们再看向另一个程序:
#include <stdio.h>
int main(void)
{
    for (int i = 0; i <= 10; i++)
    {
        printf("#\\n");
    }
}
#,但是出现了11个.如果我们不知道发生了什么问题(因为我们的程序确实是按照我们写的来正常运行的),我们可以在我们的程序里加入另一个print行来帮助我们:#include <stdio.h>
int main(void)
{
    for (int i = 0; i <= 10; i++)
    {
        printf("i is %i\\n", i);
        printf("#\\n");
    }
}
i从 0 开始,直到为 10 后停止,但是我们本应让它到达10的时候就停止.如果我们写代码的时候没有任何的留白,像下面这样,它仍然是正确的:
#include <stdio.h>
int main(void)
{
	for (int i = 0; i < 10; i++)
	{
		printf("i is %i\\n", i);
		printf("#\\n");
	}
}
style50 buggy2.c,然后看看那些关于我们应该如何改变的建议.所以回顾一下,我们有三种工具帮助我们改善我们的代码:
help50printfstyle50在我们的计算机里,我们有一种叫做RAM(random-access memory,随机存取存储器)的芯片,存储了短期内需要使用的数据.我们可能在我们的硬盘中长期保存文件(或者SSD),但是当我们打开它而且对它做出修改的时候,它就被拷贝到RAM中.尽管内存的空间更小,而且是暂时性的(因为断电时就会全部消失),但是它很快.
我们可以这样想,字节在内存里的存储是像网格一样的.

在C语言中,我们创造了一个变量的类型char,它的大小正好是一个字节,所以正好可以物理地存储在内存中的这样一个小方格里.一个4个字节的整型,则要占用4个这样的小格子.