西邮Linux面试题总结

static关键字

  • static修饰局部变量

生命周期:静态变量在程序运行之前创建,在程序的整个运行期间始终存在,直到程序结束。

注意: 静态变量,只改变了它的存储类型(即生命周期),并没有改变它的作用域,变量b还是只能在test函数内部使用。
静态本地变量, 具有全局的生存期, 只初始化一次, 离开函数后仍然存在, 具有函数内的局部作用域.
静态本地变量实际上是特殊的全局变量, 都位于相同的内存区域, 即使在声明时未赋初值, 也会默认初始化为0

  • static修饰全局变量

相当于私有的全局变量, 作用域只限于该源文件.

static与函数

  • 外部函数 : 如果在当前文件中定义的函数允许其他文件访问, 调用, 就成为外部函数, C语言规定, 不允许有同名的外部函数.
  • 内部函数 : 如果在当前文件中定义的函数不允许其他文件访问, 调用, 只能在内部使用, 就称为内部函数. C语言规定不同的源文件可以有同名的内部函数, 并且互不干扰.
    所以如果要定义外部函数完整的定义是要加上extern关键字. 不过因为默认情况下, 所有的函数就是外部函数, 所以一般简化.
    static修饰函数
    1.定义内部函数
static void test() {
	printf("dsf");
}

2.声明内部函数

 1 #include <stdio.h>
 2 
 3 static void test();
 4 
 5 int main(int argc, const char * argv[])
 6 {
 7     test();
 8     return 0;
 9 }
10 
11 static void test() {
12     printf("调用了test函数");
13 }

在第11行定义了一个test函数,这是一个内部函数,接着在第3行对test函数进行提前声明,然后就可以在第7行可以调用test()函数了
总结 :

  • static在定义函数时, 在函数的最左边加上static可以把该函数声明为内部函数, 这样该函数就只能在其定义所在的文件中使用. 如果在不同的文件中有同名的内部函数, 则互不干扰.
  • static也可以用来声明一个内部函数.

1>宏与typedef的区别:
(1)宏只是简单的替换, 而typedef可以看成是彻底的"封装"
例:#define X int*
X a, b;
只有a是指针
typedef int* X
X a, b;
a, b都是指针
(2)可以用其他类型说明符对宏定义的类型进行拓展, 而typedef不可以
例:#define X int
unsigned X a; 可以

typedef X int; unsigned X a;不可以
2>#用来将宏参数转换为字符串, 也就是在宏参数的开头和末尾添加引号, 例如:

#define A(x) #x

printf("%s", A(hello, world));
// 将会被展开为
printf("%s", "hello, world");

3>##称为连接符, 用来将宏参数和其他的串连接起来. 例如:

#define A(a, b) a##e##b
#define B(a, b) a##b##00

printf("%f\n", A(1, 2));
printf("%d\n", B(11, 22));
// 将会被展开为
printf("%f\n", 1e2);
printf("%d\n", 112200);

4>如果一个宏的值中有其他宏的名字, 而宏定义中无#或##, 则会先进行宏参数的展开, 再展开当前宏.例如:

#define YEAR 2018
#define LEVELONE(x) "XiyouLinux "#x"\n" 
#define LEVELTWO(x) LEVELONE(x)
#define MULTIPLY(x,y) x*y
int main(int argc, char *argv[])
{
int x = MULTIPLY(1 + 2, 3);
printf("%d\n", x);
printf(LEVELONE(YEAR));
printf(LEVELTWO(YEAR));
}

%zu 和size_t

  • size_t 在32位和64位的定义不同, 分别为unsigned int 和unsigned long

  • %zu : %zu输出size_t型, 为什么要有%zu, 因为在32位下, size_t被定义为unsigned int 可以用%u输出, 而在64位下, size_t被定义为unsigned long, 可以用%lu输出, 为了使程序可以跨平台,使代码具有较好的可移植性, 设计了%zu用来输出size_t型

浮点数的存储

十进制8.25的二进制是1000.01
->1.00001*2^3(3指数, 00001尾数)
浮点数中1.x*2^y也就是说1是固定的,2也是不变的,所以在内存中不用存储,在内存中只存有x和y也就是尾数和指数,当然还有符号位.
在这里插入图片描述

浮点数在内存中无法精确存储, float的有效位数只有7位(包括整数部分和小数部分), 超过7位之后均为无效数字, double的有效位数有16位, 超过16位之后均为无效数字.
判断浮点数是否相同:由于精度问题, 不可将浮点变量用 == 或 != 与数字比较, 应该设法转化为>= 或 <= 之类的形式
例:要判断float类型的变量i与0的比较
if ((x >= -0.00001) && (x <= 0.00001)) {
printf(“相等\n”);
}
也就是
if (fabs(i-0) < 1e-6) {
printf(“相等\n”);
}

printf, scanf的返回值

printf返回输出的字符的个数
scanf返回正确读取到的字符的个数
如果输入数据与指定格式不符,则会产生输入错误。遇到输入错误,scanf函数会立即终止,返回已经成功读取的数据的个数。
所以,通过scanf函数的返回值和指定输入数据的个数(由格式符决定)的比较,可以判断数据输入是否成功。

大小端

个人pc一般都是小端序, 数据在内存中存放时低字节对应低地址, 高字节对应高地址.
读取时从高地址往低地址读取.
当定义一个变量时,系统就会为这个变量分配一定的存储空间。

1 int main()
2 {
3     char a = 'A'; 
4     
5     int b = 10;
6     
7     return 0;
8 }

1> 在64bit环境下,系统为变量a、b分别分配1个字节、4个字节的存储单元。也就是说:

  • 变量b中的10是用4个字节来存储的,4个字节共32位,因此变量b在内存中的存储形式应该是0000 0000 0000 0000 0000 0000 0000 1010。

  • 变量a中的’A’是用1个字节来存储的,1个字节共8位,变量a在内存中的存储形式是0100 0001
    2> 上述变量a、b在内存中的存储情况大致如下表所示:
    在这里插入图片描述

  • 从图中可以看出,变量b占用了内存地址从ffc1~ffc4的4个字节,变量a占用了内存地址为ffc5的1个字节。每个字节都有自己的地址,其实变量也有地址。变量存储单元的第一个字节的地址就是该变量的地址。变量a的地址是ffc5,变量b的地址是ffc1。

  • 内存寻址是从大到小的, 也就是说做什么事都会先从内存地址较大的字节开始,因此系统会优先分配地址值较大的字节给变量。由于是先定义变量a、后定义变量b,因此你会看到变量a的地址ffc5比变量b的地址ffc1大。

  • 注意看表格中变量b存储的内容,变量b的二进制形式是:0000 0000 0000 0000 0000 0000 0000 1010。由于内存寻址是从大到小的,所以是从内存地址最大的字节开始存储数据,存放顺序是ffc4 -> ffc3 -> ffc2 -> ffc1,所以把前面的0000 0000都放在ffc2~ffc4中,最后面的八位0000 1010放在ffc1中。

gcc 的编译过程

.c ->.i -> .s -> .o -> a.out

  • 预处理:删除注释, 宏展开和宏替换, 处理条件编译, 文件包含等, 生成.i文件
  • 编译:生成汇编文件.s, 生成相应的汇编代码, 会检查语法等
  • 汇编:汇编代码对应生成机器码, 叫做目标文件.o
  • 链接:所有目标文件和库在一起链接, 在这个过程可以找到函数的定义从而修正假的函数地址, 得到可执行文件.

负数的二进制形式

1 int main()
2 {
3     int b = -10;
4     return 0;
5 } 

在第3行定义了一个整型变量,它的值是-10。-10在内存中怎样存储的呢?其实任何数值在内存中都是以补码的形式存储的

  • 正数的补码与原码相同。比如9的原码和补码都是0000 1001
  • 负数的补码等于它正数的原码取反后再+1.

那么-10的补码计算过程如下:
1> 先算出10的二进制形式:0000 0000 0000 0000 0000 0000 0000 1010

2> 对10的二进制进行取反:1111 1111 1111 1111 1111 1111 1111 0101

3> 对取反后的结果+1:1111 1111 1111 1111 1111 1111 1111 0110

因此,整数-10在内存中的二进制形式是:1111 1111 1111 1111 1111 1111 1111 0110

第二种计算-10的补码的方法:

1> 先写出-10的原码: 1000 1010

2> 在取反(符号位不变)得到反码: 1111 0101

3> 在+ 1得到-10的补码: 1111 0110

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值