程序员面试宝典笔记4-位运算与嵌入式编程

程序员面试宝典笔记4-位运算与嵌入式编程

位制转换

面试例题1:求下列程序输出结果_______

printf("%f\n", 5);
printf("%d\n", 5.01);

答案:
0.000000
1889785610

解析:
参考:https://blog.csdn.net/yahohi/article/details/7701434

5 是int 类型,在32位系统中,占4个字节;
printf()函数中,%f 是 double 类型的占位符,占8个字节。所以,
printf("%f\n", 5); 内存访问越界,会发生不可预估的输出。
(printf输出float型时,会自动转化成double型;)

内存越界又为啥是输出为 0 呢???
在32位系统中,5表示为:00000000,00000101,printf() 取得时候呢又是取64位,故取了好多的0,。因为最后按照(有效数字)×(基数2)pow(指数)的方式来取数,自然结果是0。

printf("%d\n", 5.01); : 5.01是按照 double 存储的,也就是8个字节(64bits)。而printf()取4个字节。
5.01是double类型,内存中占8个字节,保存在缓冲区。而%d为整型,占4个字节,printf从缓冲区中读入4字节,先读到低32位的数据。也就是说printf输出的应该是5.01以double类型保存数剧的低32位。

5.01的double类型,在内存的的表示为0x40140a3d70a3d70a。

所以printf("%d\n", 5.01);输出的是0x40140a3d70a3d70a 的低32位 (转化成十进制)。

面试例题2:求下列程序是否有错,若有错在哪里______

#include <iostream>
using namespace std;
struct a {
	int x : 1;
	int y : 2;
	int z : 32;
};
int main()
{
	a d;
	cout << &d <<endl;
	d.z = d.x + d.y;
	printf("%d %d %d %d\n", d.x, d.y, d.z, sizeof(d));
	system("pause");	return 0;
}

结构体位制概念
int z:33; 定义整形变量 z 为33位,超过了sizeof( int ) 个字节,不合法,越界,报错。

int z:33;int z:32;
改正后实际运行结果为:
008FFD00
0 -2 -2 8

面试例题2:求下列程序是否有错,若有错在哪里______

#define BIT_MASK(bit_pos) (0x01<<(bit_pos))
int Bit_Reset(unsigned int *val, unsigned char pos)
{
	if (pos >= sizeof(unsigned int) * 8)
		return 0;
	*val = (*val && BIT_MASK(pos));
	return 1;
}

位操作符有:&, | ,~,^ , <<,>>
逻辑符号有:&&,||,!

此题应该为:
*val = (*val && BIT_MASK(pos));*val = (*val & BIT_MASK(pos));

面试例题3:下面那个进制能表示 13 ∗ 16 = 244 13 * 16 =244 1316=244是正确的?
在这里插入图片描述
在这里插入图片描述
面试例题4:下列程序的输出代表什么?

int main()
{
	const char *p = "a";
	int i1 = (int)"a";
	int i2 = (int)p;

	cout << i1 << endl;
	cout << i2 << endl;

	system("pause");

	return 0;
}

输出结果:10058552,

int i1 = (int)“a”;
cout<< i1 <<endl;
结果是10058552,此处就是把这个字符串的首字母在常量区的内存地址转化为int 型再赋值i1;
int i2 = (int)p;
p 是指向常量区字符串“a”的char * 指针,此处将p 的值(即常量存储区字符串首地址)转化为 int 型再赋值给 i2。

面试例题5:下列程序的输出是什么?

#include <iostream>
using namespace std;
int main()
{
	unsigned short int i = 0;
	int j = 8, p;
	p = j << 1;
	i = i - 1;   
	cout << "\n i = " << i << endl;
	cout << "\n p = " << p << endl;
	system("pause");
	return 0;
}

输出结果是:65535, 16
左移 或者 右移 是最有效的乘除2 的方式之一;
无符号的 -1 表示为 65535, 有符号的 -1 表示为 -1;

面试例题5:下列程序的输出是什么?

#include <iostream>
using namespace std;

union {
	unsigned char a;
	unsigned int i;
}u;

int main()
{
	u.i = 0xf0f1f2f3;
	cout << hex << u.i << endl;
	cout << hex << int(u.a) << endl;
	system("pause"); return 0;
}
  • 大端模式:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中;
  • 小端模式:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。

这个题目的程序可以改编一下用来处理器的大端小端模式;具体的数据在内存中的存放如下图:
在这里插入图片描述
改编:用来确定 大端模式 还是 小端模式

#include <iostream>
using namespace std;

union {
	unsigned char a;
	unsigned int i;
}u;

int main()
{
	u.i = 0xf0f1f2f3;
	if (int(u.a) == 0xf3)
		cout << "小端模式" << endl;
	else
		cout << "大端模式" << endl;
	system("pause"); return 0;
}

面试例题6:完成下列程序编写?
在这里插入图片描述

#include <iostream>
using namespace std;

#define BIT_MASK(pos) (0x01<<(pos)) 

int main()
{
	int a=0xF7;
	int pos = 3; //bit3
	// (1) bit3置1
	// 1111 0111 -> 1111 1111
	a |= (BIT_MASK(pos));
	cout << a << endl;
	// (2) bit3清零
	// 1111 1111 -> 1111 0111
	a &= (~BIT_MASK(pos));
	cout << a << endl;

	system("pause"); return 0;
}

这里我使用了一个宏定义来生成MASK,这个是嵌入式编程中常用到的;
a = 0xF7 ==> 1111 0111 ==> 247,需要改变的 bit3 我为了试验清楚就设置为 0.
输出为 255, 247 。先置1成255, 再清零 bit3 位,回复原来大小。

面试例题7:下列程序的输出是什么?

int main()
{
	int *p=NULL;
	int *pa = p + 15;
	printf("%x ", pa);
	system("pause"); return 0;
}

p 是一个空指针,值为0x00000000{???},{ ??? } 表示指针指向对象未知;sizeof( p )=4Byte.
int *pa = p + 15; 即pa 指向的是 p 偏移15个int 类型的字节的单元。15 * 4=60 ⇒ 0x3C
所以pa 的值(就是个地址)为0x3C.

嵌入式编程

面试例题1 :In embedded system, we usually use the keyword “volatile”, what does the keyword mean ?
在这里插入图片描述
解析:

当一个对象可能会在编译器的控制或者检测之外被改变时,例如一个被系统始终更新的变量,那么该对象应该声明成 volatile。因此编译器执行的某些例行优化行为不能应用在已指定为 volatile 的对象上。

vilatile 限定修饰符的用法与 const 非常相似------都是作为类型的附加修饰符。例如:
(1)volatile int display_register;
(2)volatile Task *curr_task;
(3)volatile int ixa{ max_size };
(4)volatile Screen bitmap_buf;

display_register 是一个 int 型的volatile 对象;
curr_task 是一个指向 (volatile 的Task类对象) 的指针;
ixa 是一个 volatile 的整形数组,数组的每个元素都被认为是 volatile的;
bitmap_buf 是一个 volatile 的Screen 类对象,它的每个数据成员都被视为 volatile。

volatile 修饰符的主要目的是提示编译器该对象的值可能在编译器未检测到的情况下被改变,因此编译器不能武断地对引用这些对象的代码做优化处理。

面试例题3:关键字 const 有什么含义?下面的声明都是什么意思?

const int a;
int const a;
const int *a;
int *const a;
int const *const a ;

解析:
const int a; <==> int const a; 修饰 a 是一个常整型数。
const int *a; 表示 a 是一个指向const 对象的指针,但a 本身不是const ,是可以被修改的。
这个来个示例程序:

const int *a;
int b=30;
a=&b;
cout<<*a<<endl;	// *a=30
b=40;
cout<<*a<<endl;	// *a=40
*a = 50;		// error:you cannot assign to a variable that is const.

int *const a; 是a 是一个指定整型数的常指针。
int const *a const; 最后一个意味着 a 是一个指向常整型数的常指针。

面试例题4:关键字 volatile 有什么含义? 给出三个不同的例子。
在这里插入图片描述

面试例题5
(1)一个参数可以即是 const 又是 volatile 吗?
(2)一个指针可以是 volatile 吗?解释为啥?

解析:
(1)可以,一个例子就是只读的状态寄存器。它是 volatile ,因为他可能被意想不到地改变;他又是 const ,因为程序不应该去修改它。
(2)可以,尽管这并不是很常见。一个例子是当一个中断服务子程序修改一个指向一个 buffer 的指针时。【不太理解!】

面试例题6:找错

int square(volatile int *ptr)
{
	return *ptr * *ptr;
}

解析:
这段代码的目的是返回 ptr 指向对象的平方值。
但是呢,ptr 是一个指向 volitale对象的指针,这个值可能意想不到的改变。
相当于下面的代码:

int square(volatile int *ptr)
{
	int a, b;
	a = *ptr;
	b = *ptr;
	return a * b;
}

因为上述 volatile 的特性可知,a 和 b 可能不一样,所以就得不到正确的值。

应该改为如下:

int square(volatile int *ptr)
{
	int a, b;
	a = *ptr;
	return a * a;
}

面试例题7:嵌入式系统经常具有要求程序员去访问某些特定位置的内存的特点。在某些工程中,要求设置一绝对地址为0x67a9 的整型变量的值为 0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。

解析:
为了访问一个绝对地址把一个整型数强制转换为一个指针时合法的。这一问题的实现方式随着个人风格不同而不同。

int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa55;

一个晦涩的方法是:
*(int * const)(0x67a9) = 0xaa55;

面试例题8:下面程序的运行结果为:________?【不太明白】

int main()
{
	char *ptr;
	if ((ptr = (char *)malloc(0)) == NULL)
		puts("Got a null pointer");
	else
		puts("Got a valid pointer");

	system("pause"); return 0;
}

解析:
答案为 “Got a valid pointer”.
在这里插入图片描述
如果将上题的程序修改为:
在这里插入图片描述
若求 ptr 的strlen 值和 sizeof() 值,改代码的输出为 “Got a null pointer”

面试例题9:In little-endian systems, what is the result of following C program ?

#include <iostream>
using namespace std;

typedef struct bitstruct {
	int b1 : 5;
	int : 2;
	int b2 : 2;
}bitstruct;

void main()
{
	bitstruct b;
	cout << sizeof(b) << endl;
	memcpy(&b, "EMC EXAMINATION", sizeof(b));
	printf("%d ,%d\n", b.b1, b.b2);
	system("pause"); return;
}

解析:
在这里插入图片描述

static

面试例题1:关键字static 的作用是什么?
在这里插入图片描述
在这里插入图片描述

面试例题2:下面程序的运行结果为:________.

#include <iostream>
using namespace std;

int sum(int a)
{
	auto int c = 0;
	static int b = 3;
	c += 1;
	b += 2;
	return (a + b + c);
}

void main()
{
	int I;
	int a = 2;
	for (I = 0; I < 5; I++)
		printf("%d,", sum(a));

	system("pause"); return;
}

这个题目是计算机二级C语言的题目~~~,记得之前写51单片机的时候学过。

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值