— 由 @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
,然后看看那些关于我们应该如何改变的建议.所以回顾一下,我们有三种工具帮助我们改善我们的代码:
help50
printf
style50
在我们的计算机里,我们有一种叫做RAM(random-access memory,随机存取存储器)的芯片,存储了短期内需要使用的数据.我们可能在我们的硬盘中长期保存文件(或者SSD),但是当我们打开它而且对它做出修改的时候,它就被拷贝到RAM中.尽管内存的空间更小,而且是暂时性的(因为断电时就会全部消失),但是它很快.
我们可以这样想,字节在内存里的存储是像网格一样的.
在C语言中,我们创造了一个变量的类型char
,它的大小正好是一个字节,所以正好可以物理地存储在内存中的这样一个小方格里.一个4个字节的整型,则要占用4个这样的小格子.