论文下载链接:论文|第二学期| 2015-16
时间: 3小时
总分数:100
注意:-
- 共分为三个部分。 A节为20分, B节为50分, C节为30分。
- 尝试所有问题。每个问题都带有标记。
- 必要时假定合适的数据。
尝试两个部分:(15 * 2 = 30)
3.什么是预处理器指令?解释其中的任何三个。
- 条件编译:条件编译指令有助于编译程序的特定部分,或者让我们根据某些条件跳过对程序某些特定部分的编译。在上一篇文章中,我们讨论了两个这样的指令’ ifdef ‘和’ endif ‘。在这篇文章中,我们将讨论#ifndef , #if , #else和#elif 。
- #ifdef :此指令是最简单的条件指令。此块称为条件组。如果定义了宏名,则受控文本将包含在预处理器输出中。条件内的受控文本将包含预处理指令。仅在条件成功时才执行它们。您可以将它们嵌套在多个层中,但是必须将它们完全嵌套。换句话说,“#endif”始终匹配最接近的“ #ifdef”(或“ #ifndef”或“ #if”)。同样,您不能在一个文件中开始条件组,而在另一个文件中完成它。
句法:
#ifdef MACRO controlled text #endif /* macroname */
- #ifndef :我们知道,如果#ifdef指令中定义了宏名,则#ifdef指令后的语句块将正常执行,但是如果未定义,则编译器将简单地跳过该语句块。 #ifndef指令与#ifdef指令相反。对于#ifndef,仅当未定义宏或带有#ifndef的标识符时,才会执行#ifndef和#endif之间的语句块。
句法 :ifndef macro_name statement1; statement2; statement3; . . . statementN; endif
如果未使用#define指令定义名称为“ macroname”的宏,则仅执行语句块。
- #if,#else和#elif :这些指令可以一起使用,并使用某些条件控制程序部分的编译。如果带有#if指令的条件的结果为非零值,那么将立即执行#if指令后的行组,否则,如果带有#elif指令的条件的结果为非零值,则该行组#elif指令之后将立即执行,否则#else指令之后的行将被执行。
句法:#if macro_condition statements #elif macro_condition statements #else statements #endif
例子:
#include
#define gfg 7 #if gfg > 200 #undef gfg #define gfg 200 #elif gfg < 50 #undef gfg #define gfg 50 #else #undef gfg #define gfg 100 #endif int main() { std::cout << gfg; // gfg = 50 } 输出:
50
注意#if,#elif和#else链式指令的整个结构如何以#endif结尾。
- #ifdef :此指令是最简单的条件指令。此块称为条件组。如果定义了宏名,则受控文本将包含在预处理器输出中。条件内的受控文本将包含预处理指令。仅在条件成功时才执行它们。您可以将它们嵌套在多个层中,但是必须将它们完全嵌套。换句话说,“#endif”始终匹配最接近的“ #ifdef”(或“ #ifndef”或“ #if”)。同样,您不能在一个文件中开始条件组,而在另一个文件中完成它。
- 行控制(#line) :每当我们编译程序时,程序中都有发生某些错误的机会。只要编译器在程序中发现错误,它就会为我们提供在其中找到错误的文件名,行列表以及错误所在的确切行号。这使我们很容易找到并纠正错误。
但是,我们可以使用#line指令控制编译器在编译错误期间应提供哪些信息。
句法:#line number "filename"
number –将分配给下一个代码行的行号。从此以后,连续行的行号将一一增加。
“文件名” –可选参数,允许重新定义将显示的文件名。 - 错误指令(#error) :在编译过程中在程序中找到该指令时,该指令将中止编译过程,并产生一个可选的错误,可以将其指定为参数。
句法:#error optional_error
在这里, optional_error是用户指定的任何错误,当在程序中找到该伪指令时将显示该错误。
例子:#ifndef GeeksforGeeks #error GeeksforGeeks not found ! #endif
输出:
error: #error GeeksforGeeks not found !
4.(i)详细说明程序的加载和链接。
- 加载程序是操作系统的程序,它将可执行文件从磁盘加载到主内存(RAM)中以供执行。它将内存空间分配给主内存中的可执行模块,然后将控制权转移到程序的开始指令。
例子:
akash @aix(/ u / akash) #cat./ ak1.cpp #include
int main() { printf("Testing of Loader !"); return 0; } 通过xlC编译器进行编译:
akash @aix(/ u / akash) #xlC – o ak1.out./ ak1.cpp akash @aix(/ u / akash) #ls – lrt ak1 * -rw – rw – r– 1 akash dev 74 Nov 12 06 : 10 ak1.cpp
– rwxrwxr – x 1 akash dev 8562 Nov 12 06 : 34 ak1.out akash @aix(/ u / akash) #运行可执行文件时真正发生的情况:也可以使用strace命令。
akash@aix(/u/akash)# truss ./ak1.out
execve(“./ak1.out”, 0x2FF20A00, 0x200138A8) argc: 1
read_sysconfig(0xF06F8278, 0x00000010, 0xFFFFFFF9, 0x10000000, 0x200007BC, 0x000000C0, 0x06010000, 0xF076A0F0) = 0x00000000
sbrk(0x00000000) = 0x20000998
vmgetinfo(0x2FF20350, 7, 16) = 0
sbrk(0x00000000) = 0x20000998
sbrk(0x00000008) = 0x20000998
__libc_sbrk(0x00000000) = 0x200009A0
loadquery(2, 0x200009C8, 0x00001000) = 0
__loadx(0x0A040000, 0xF06F599C, 0x00000000, 0xF05BE208, 0x20001D20) = 0xF05BFD64
loadbind(0, 0xF0760BBC, 0xF06D0E54) = 0
kfcntl(0, F_GETFL, 0x00000000) = 67110914
kfcntl(1, F_GETFL, 0x00000000) = 67110914
kfcntl(2, F_GETFL, 0x00000000) = 67110914
kfcntl(2, F_GETFL, 0x00000000) = 67110914
kioctl(1, 22528, 0x00000000, 0x00000000) = 0
Testing of Loader !kwrite(1, ” T e s t i n g o f L”.., 19) = 19
kfcntl(1, F_GETFL, 0x00000070) = 67110914
kfcntl(2, F_GETFL, 0x2FF22FFC) = 67110914
_exit(0)显示的第一个调用是’ execve() ‘,它实际上是加载程序。该加载器创建的过程涉及:
- 读取文件并为该进程创建地址空间。
- 创建指令,数据和程序堆栈的页表条目,并初始化寄存器集。
- 然后,执行通常会导致页面错误的程序第一条指令的跳转指令,并将指令的第一页存储到内存中。
- 链接这是最后一个阶段,在此阶段中完成了所有函数调用及其定义的链接。链接器知道所有这些功能的实现位置。 Linker还会做一些额外的工作,它会在程序的开始和结束时向我们的程序中添加一些额外的代码。例如,有一个代码需要设置环境,例如传递命令行参数。使用$ size filename.o和$ size filename可以轻松地验证此任务。通过这些命令,我们知道输出文件如何从目标文件增加到可执行文件。这是因为链接器在我们的程序中添加了额外的代码。
请注意,默认情况下,GCC会进行动态链接,因此在上述程序中会动态链接printf()。有关静态和动态链接的更多详细信息,请参考本文档,本文档和本文档。
4.(ii)用C编写一个程序,该程序将从键盘读取一个正数并以相反的顺序打印它。
例子:
Input: 24578
Output: 87542
#include
/* Iterative function to reverse digits of num*/
int reversDigits(int num)
{
int rev_num = 0;
while (num > 0) {
rev_num = rev_num * 10 + num % 10;
num = num / 10;
}
return rev_num;
}
/* Driver program to test reversDigits */
int main()
{
int num;
scanf("%d", &num);
printf("Reverse of no. is %d",
reversDigits(num));
return 0;
}
输出:
2654
5.假设一个文件包含学生的记录,而每个记录都包含一个学生的姓名和年龄。编写一个C程序来读取这些记录,并按名称按顺序显示它们。
// C program to read Student records
// like id, name and age,
// and display them in sorted order by Name
#include
#include
#include
// struct person with 3 fields
struct Student {
char* name;
int id;
char age;
};
// setting up rules for comparison
// to sort the students based on names
int comparator(const void* p, const void* q)
{
return strcmp(((struct Student*)p)->name,
((struct Student*)q)->name);
}
// Driver program
int main()
{
int i = 0, n = 5;
struct Student arr[n];
// Get the students data
arr[0].id = 1;
arr[0].name = "bd";
arr[0].age = 12;
arr[1].id = 2;
arr[1].name = "ba";
arr[1].age = 10;
arr[2].id = 3;
arr[2].name = "bc";
arr[2].age = 8;
arr[3].id = 4;
arr[3].name = "aaz";
arr[3].age = 9;
arr[4].id = 5;
arr[4].name = "az";
arr[4].age = 10;
// Print the Unsorted Structure
printf("Unsorted Student Records:\n");
for (i = 0; i < n; i++) {
printf("Id = %d, Name = %s, Age = %d \n",
arr[i].id, arr[i].name, arr[i].age);
}
// Sort the structure
// based on the specified comparator
qsort(arr, n, sizeof(struct Student), comparator);
// Print the Sorted Structure
printf("\n\nStudent Records sorted by Name:\n");
for (i = 0; i < n; i++) {
printf("Id = %d, Name = %s, Age = %d \n",
arr[i].id, arr[i].name, arr[i].age);
}
return 0;
}
输出:
Unsorted Student Records:
Id = 1, Name = bd, Age = 12
Id = 2, Name = ba, Age = 10
Id = 3, Name = bc, Age = 8
Id = 4, Name = aaz, Age = 9
Id = 5, Name = az, Age = 10
Student Records sorted by Name:
Id = 4, Name = aaz, Age = 9
Id = 5, Name = az, Age = 10
Id = 2, Name = ba, Age = 10
Id = 3, Name = bc, Age = 8
Id = 1, Name = bd, Age = 12