Linux开发环境及其应用 《第11周单元测验》及其解析

1、下段程序中变量a,b以及常数120, 250分别存放在进程的哪个内存段中?

static int a = 120;
void modify(void)
{
    int b;
    scanf("%d", &b);
    a += b + 250;
}

A、a在数据段,所有的C语言常量都在数据段,所以,除了b之外,全在数据段
B、变量a和常量120在数据段,b在用户栈段,250在指令段
C、a和120在数据段,b和250在用户栈段
D、无论常量还是变量,都是程序处理的数据,所以都在数据段

B、在main函数运行前,加载程序负责初始化携带初值的可读写型变量a在数据段的初值为120,所以常数120在数据段,它和a是一回事,只是a的初始值而已,而250是编译之后指令的一个操作数,叫“立即数寻址”,也就是说250是一条指令的操作数之一,是一条指令的一部分,存放在指令段

有一点迷惑的是字符串常量放置在数据段,意思就是如果函数中有字符串常量,而不是int之类的,就在数据段。
Linux开发环境及其应用 《第11周单元测验》及其解析_第1张图片

2、在你的Linux系统上将下列程序编译生成可执行文件,记录可执行文件的大小。

#include 
#include 
#define N (1024 * 1024)
int a[N] = { 2 };
int main(void)
{
    int i, sum = 0;
    for (i = 0; i < N; i++)
        a[i] += rand();
    for (i = 0; i < N; i++)
        sum += a[i];
    printf("sum = %d\n", sum);

将第4行修改为

int a[N];

重新编译生成可执行文件。则两次生成的可执行文件的大小比较结果为:

A、两文件大小完全相同
B、文件大小差不多,后一个文件要少4个字节,因为一个整数占4字节
C、文件差别较大,前者比后者大很多
D、文件差别较大,后者比前者大很多

没有初始化的数据不在指令段,在数据段,主要差距就在这里
Linux开发环境及其应用 《第11周单元测验》及其解析_第2张图片
全局数组只要是初始化了,无论初始化了一个元素或者全部元素,编译生成可执行文件(即狭义的“程序”)时,会把这个数组的全部内容逐比特记录到可执行文件中,进程启动时分配指定大小空间并把可执行文件中记录的初值初始化它。如果数组未初始化,可执行文件里只需要记录一下这个全局变量有多大就可以了,进程启动时分配指定大小空间并清零。可以尝试把那一行修改为
int a[N] = { 0 };
在现代的Linux中处理得跟未赋初值一样,在早先的Unix中处理得跟有赋初值一样。显然新的处理方法更优。

3、下列程序编译后在Linux上运行:

#include 
int main(void)
{
    int n;
    scanf("%d", &n);
    printf("n2 = %d\n", n * n);
}

程序启动后,输入1379并按下回车,花费时间3秒,然后程序运行结束。在进程的生存周期内,估测一下大概有多长时间处于阻塞状态,多长时间处于运行状态。

A、状态切换完全由操作系统调度程序控制,根据当时的运行环境动态调整,所以无法做出判断
B、进程绝大多数时间处于阻塞状态,处于运行态的时间极短,现在计算机的计算能力应在1ms以内
C、程序运行期间,进程始终处于运行态
D、进程始终处于阻塞态

4、C语言程序中所有未赋初值的变量,可执行程序运行时Linux会把它们自动初始化为0.

×

程序加载时把为赋初值的变量自动初始化为0,这仅适用于全局变量或者函数内部的静态变量。对于普通的函数内定义的局部变量,它们只有函数调用时才分配存储空间,函数返回后空间释放,存储空间在栈内分配。未赋初值的变量初值,就是分配到的栈存储单元前一阶段使用者的残留值,初值难以预测。

5、文件testm.c的源码如下

#include 
#include 
void f(int i)
{
    int a[8];
    printf("begin\n");
    a[i] = 1111;
    printf("i = %d, a[i] = %d\n", i, a[i]);
    printf("a[0]~a[7]:(%p~%p), &a[i]=%p\n", &a[0], &a[7], &a[i]);
}
void main(int argc, char **argv)
{
    f(atoi(argv[1]));
}

执行结果如下

linux$ ./testm 6
begin
i = 6, a[i] = 1111
a[0]~a[7]:(0xbfd033bc~0xbfd033d8), &a[i]=0xbfd033d4
linux$ ./testm 8
begin
i = 8, a[i] = 1111
a[0]~a[7]:(0xbfe33d1c~0xbfe33d38), &a[i]=0xbfe33d3c
*** stack smashing detected ***: <unknown> terminated
Aborted
linux$ ./testm 128
begin
i = 128, a[i] = 1111
a[0]~a[7]:(0xbfabe51c~0xbfabe538), &a[i]=0xbfabe71c
linux$ ./testm -128
begin
i = -128, a[i] = 1111
a[0]~a[7]:(0xbf9f5d5c~0xbf9f5d78), &a[i]=0xbf9f5b5c
linux$ ./testm -99999
begin
Segmentation fault
linux$ ./testm 99999
begin
Segmentation fault

这说明:尽管借助CPU中MMU提供的机制Linux提供了内存越界保护,但是,C语言程序中越界访问数组,也就是说访问超出了数组元素个数,除非这个越界导致越界后的地址值使得访问违背了PTE中的权限限制,否则,访问照样进行,系统不给出任何提示。

6、在嵌入式Linux系统中无硬盘等辅助存储设备,无法做到提供比物理内存更多的虚拟内存,而且,系统上运行的多个进程内存需求量小,物理内存足够用,所以不需要虚拟地址到物理地址的转换。

×

多个进程,每个进程都有自己独立的虚拟地址空间,由于多个进程是独立的,在虚拟地址空间的使用上,完全可能重叠,就是说多个进程都访问同一个虚拟地址,当然应该映射到不同的物理页面。也就是说,仍然需要虚拟内存的这个功能:把多个独立的虚拟地址空间映射到物理上唯一的物理地址空间。所以,仍然需要拟地址到物理地址的转换。

7、忙等待的主要危害是导致内存泄漏,有可能会导致系统崩溃。

×

8、在32位Linux系统中,每个进程最多有4GB寻址空间,但是并不是每一段寻址空间都分配了实际的内存。进程实际使用的虚拟内存,一般会小于4GB。

你可能感兴趣的:(Linux,linux)