• 嵌入式相关1


    1、 如何在C中初始化一个字符数组。

    这个问题看似很简单,但是我们要将最简单的问题用最严谨的态度来对待。关键的地方:初始化、字符型、数组。最简单的方法是char array[];。这个问题看似解决了,但是在初始化上好像还欠缺点什么,个人认为:char array[5]={'1','2','3','4','5'};或者char array[5]={"12345"};或者char array[2][10]={"China","Beijing"};也许更符合"初始化"的意思。

    2、 如何在C中为一个数组分配空间。

    最简单的方法是:char array[5];意思是分配给数组array一个5个字节的空间。但是我们要知道在C中数组其实就是一个名字,其实质含义就是指针,比如char array[];是到底分配的多少空间?所以我们要将其分成为两种不同的形式给出答案:

    一种是栈的形式:char array[5];

    一种是堆的形式:char *array; array=(char *)malloc(5);//C++: array=new char[5];

    堆和栈的含义其实我也没弄太透彻,改天明白了再发一篇。

    我们要明白的是,第一种形式空间分配的大小可能会受操作系统的限制,比如windows会限制在2M;第二种形式成空间分配很灵活,想分配多少分配多少,只要RAM够大。

    3、 如何初始化一个指针数组。

    首先明确一个概念,就是指向数组的指针,和存放指针的数组。

    指向数组的指针:char (*array)[5];含义是一个指向存放5个字符的数组的指针。

    存放指针的数组:char *array[5];含义是一个数组中存放了5个指向字符型数据的指针。

    按照题意,我理解为初始化一个存放指针的数组,char *array[2]={"China","Beijing"};其含义是初始化了一个有两个指向字符型数据的指针的数组,这两个指针分别指向字符串"China"和"Beijing"。

    4、如何定义一个有10个元素的整数型指针数组。

    既然只是定义而不是初始化,那就很简单且没有争议了:int *array[10];。

    5、 s[10]的另外一种表达方式是什么。

    前面说过了,数组和指针其实是数据存在形态的两种表现形式,如果说对于数组s[],我们知道*s=s[0],那么s[10]的另一种表达方式就是:*(s+10)。

    6、 GCC3.2.2版本中支持哪几种编程语言。

    这个问题实在变态,就像问你#error的作用是什么一样。不可否认,gcc是linux下一个亮点,是一个备受无数程序员推崇的编译器,其优点省略1000字,有兴趣可以自己查,我翻了翻书,书上曰:支持C,C++,Java,Obj-C,Ada,Fortran,Pascal,Modula-3等语言,这个"等"比较要命,不过我认为已经很全了,如果认为还是不全,干脆把ASM也加上算了,不过那已经不算是编译了。

    7、 要使用CHAR_BIT需要包含哪个头文件。

    如果结合上面的问题,答题的人估计会认为自己撞鬼了,这个问题实在是……搜索了一下,应该是limits.h。

    8、 对(-1.2345)取整是多少?

    其实不同的取整函数可能有不同的结果,不过这个数没有太大的争议,答案是-1。

    9、 如何让局部变量具有全局生命期。

    具体的生命期的概念我觉得我还要好好深入的学习一下,但是这个题目还算比较简单,即用static修饰就可以了,但是只是生命期延长,范围并没有扩大,除非把这个变量定义在函数体外的静态区,不过那样就变成全局变量了,仿佛不符合题目要求。

    10、C中的常量字符串应在何时定义?

    这个问题说实话不是很理解题干的意思,据我理解,有两种情况,一种是预处理阶段,用#define定义;还有就是使用const修饰词,不过const修饰的是一个变量,其含义是"只读",称之为常量并不准确,但是确实可以用操作变量的方法当常量用。所以还是第一种比较靠谱。

    11、如何在两个.c文件中引用对方的变量。

    这个问题也问的挺含糊的,怎么说呢,最简单最直接的方法是为变量添加extern修饰词,当然,这个变量必须是全局变量。还有一种就是利用函数调用来进行变量的间接引用,比如这个C文件中的一个函数引用另外一个C中的函数,将变量通过实参的形式传递过去。不过题目既然说是引用,那么还是用第一个答案好了。

    12、使用malloc之前需要做什么准备工作。

    其实准备工作很多啊,比如你需要一台计算机之类的。玩笑话,我们首先要知道malloc的用途,简单的说就是动态的分配一段空间,返回这段空间的头指针。实际的准备工作可以这么分:需要这段空间的指针是否存在,若不存在,则定义一个指针用来被赋值,还要清楚要返回一个什么类型的指针,分配的空间是否合理;如果指针已经存在,那么在重新将新的空间头地址赋值给这个指针之前,要先判断指针是否为NULL,如果不是要free一下,否则原来的空间就会被浪费,或者出错,free之后就按照前一种情形考虑就可以了。

    13、realloc函数在使用上要注意什么问题。

    这个函数我也才知道的,汗一个。据我的初步理解,这个函数的作用是重新分配空间大小,返回的头指针不变,只是改变空间大小。既然是改变,就有变大、变小和为什么改变的问题。变大,要注意不能大到内存溢出;变小,那变小的那部分空间会被征用,原有数据不再存在;为什么改变,如果是想重新挪作他用,还是先free了吧。

    14、strtok函数在使用上要注意什么问题。

    这个问题我不知道能不能回答全面,因为实在是用的很少。这个函数的作用是分割字符串,但是要分割的字符串不能是常量,这是要注意的。比如先定义一个字符串:char array[]="part1,part2";,strtok的原形是char *strtok(char *string, char *delim);,我们将","作为分隔符,先用pt=strtok(array,",");,得到的结果print出来就是"part1",那后面的呢,要写成pt=strtok(NULL,",");,注意,要用NULL,如果被分割的字符串会被分成N段,那从第二次开始就一直要用NULL。总结起来,需要注意的是:被分割的字符串和分隔符都要使用变量;除第一次使用指向字符串的指针外,之后的都要使用NULL;注意使用这个函数的时候千万别把指针跟丢了,不然就全乱了。

    15、gets函数在使用上要注意什么问题。

    这是一个键盘输入函数,将输入字符串的头地址返回。说到要注意的问题,我还是先查了一下网上的一些情况,需要注意的就是gets以输入回车结束,这个地球人都知道,但是很多人不知道的是,当你输入完一个字符串后,这个字符串可能依然存在于这个标准输入流之中,当再次使用gets的时候,也许会把上次输入的东西读出来,所以应该在使用之后用fflush(stdin);处理一下,将输入流清空。最后也还是要注意溢出的问题。关于这个答案我比较含糊,不知道有没有高人高见?

    16、C语言的词法分析在长度规则方面采用的是什么策略?

    我无语……闻所未闻啊……还是搜索了一下,有一篇文章,地址是:http://202.117.80.9/jp2005/20/kcwz/wlkc/wlkc/03/3_5_2.htm,是关于词法分析器的。其中提到了两点策略: (1) 按最长匹配原则确定被选的词型;(2) 如果一个字符串能为若干个词型匹配,则排列在最前面的词型被选中。不知道是不是题干的要求,还是其他什么。我乃一介草民,望达人指点迷津!

    17、a+++++b所表示的是什么意思?有什么问题?

    这个东西(称之为东西一点都不过分)其实并没有语法错误,按照C对运算符等级的划分,++的优先级大于+,那么这句话会被编译器看做:(a++)+(++b),这回明白了吧。有什么问题,语法上没有问题,有的是道德上的问题!作为一个优秀的程序员,我们要力求语句的合法性和可读性,如果写这句的人是在一个team里,那么他基本会被打的半死……最后讨论一下结果:假设a之前的值是3,b是4,那么运行完这个变态语句后,a的值是4,b是5,语句的结果是8。

    18、如何定义Bool变量的TRUE和FALSE的值。

    不知道这个题有什么陷阱,写到现在神经已经大了,一般来说先要把TURE和FALSE给定义了,使用#define就可以:

    #define TURE 1

    #define FALSE 0

    如果有一个变量需要定义成bool型的,举个例子:bool a=TURE;就可以了。

    19、C语言的const的含义是什么。在定义常量时,为什么推荐使用const,而不是#define。

    首先,这个题干抽了10题回答的一个大嘴巴。关于常量的概念看来我要好好看看书了……我说过了,const修饰词可以将一个变量修饰为"只读",这个就能称为常量么?姑且认为可以。回到题目中,const是只读的意思,它限定一个变量不允许被改变,谁都不能改!既然是修饰变量,那么变量的类型就可以丰富多彩,int啊,char啊,只要C认识的都可以;但是#define就不可以了,在预处理阶段缺乏类型检测机制,有可能会出错。还有就是变量可以extern,但是#define就不可以。貌似const还可以节省RAM,这个我倒是没有考证过。至于const的用法和作用,有很多,我会总结后发上来。

    20、C语言的volatile的含义是什么。使用时会对编译器有什么暗示。

    终于最后一题了,容易么……如果这个测试是一个关于嵌入式的,那么这道题非常重要!!从词面上讲,volatile的意思是易变的,也就是说,在程序运行过程中,有一些变量可能会被莫名其妙的改变,而优化器为了节约时间,有时候不会重读这个变量的真实值,而是去读在寄存器的备份,这样的话,这个变量的真实值反而被优化器给"优化"掉了,用时髦的词说就是被"和谐"了。如果使用了这个修饰词,就是通知编译器别犯懒,老老实实去重新读一遍!可能我说的太"通俗"了,那么我引用一下"大师"的标准解释:

    volatile的本意是"易变的" 。

    由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化,但有可能会读脏数据。当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。

    精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份

    下面是volatile变量的几个例子:

    1). 并行设备的硬件寄存器(如:状态寄存器)

    2).一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

    3). 多线程应用中被几个任务共享的变量

    嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。

     

     

     

     

     

     

     

     

    常用宏定义:

    写好C语言,漂亮的宏定义很重要

    2009-12-09 17:08

    写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性 等等。下面列举一些成熟软件中常用得宏定义。。。。。。

    1,防止一个头文件被重复包含

    #ifndef COMDEF_H

    #define COMDEF_H

    //头文件内容

    #endif

    2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植。

    typedef unsigned char boolean; /* Boolean value type. */

    typedef unsigned long int uint32; /* Unsigned 32 bit value */

    typedef unsigned short uint16; /* Unsigned 16 bit value */

    typedef unsigned char uint8; /* Unsigned 8 bit value */

    typedef signed long int int32; /* Signed 32 bit value */

    typedef signed short int16; /* Signed 16 bit value */

    typedef signed char int8; /* Signed 8 bit value */

    //下面的不建议使用

    typedef unsigned char byte; /* Unsigned 8 bit value type. */

    typedef unsigned short word; /* Unsinged 16 bit value type. */

    typedef unsigned long dword; /* Unsigned 32 bit value type. */

    typedef unsigned char uint1; /* Unsigned 8 bit value type. */

    typedef unsigned short uint2; /* Unsigned 16 bit value type. */

    typedef unsigned long uint4; /* Unsigned 32 bit value type. */

    typedef signed char int1; /* Signed 8 bit value type. */

    typedef signed short int2; /* Signed 16 bit value type. */

    typedef long int int4; /* Signed 32 bit value type. */

    typedef signed long sint31; /* Signed 32 bit value */

    typedef signed short sint15; /* Signed 16 bit value */

    typedef signed char sint7; /* Signed 8 bit value */

    3,得到指定地址上的一个字节或字

    #define MEM_B( x ) ( *( (byte *) (x) ) )

    #define MEM_W( x ) ( *( (word *) (x) ) )

    4,求最大值和最小值

    #define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )

    #define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )

    5,得到一个field在结构体(struct)中的偏移量

    #define FPOS( type, field )

    /*lint -e545 */ ( (dword) &(( type *) 0)-> field ) /*lint +e545 */

    6,得到一个结构体中field所占用的字节数

    #define FSIZ( type, field ) sizeof( ((type *) 0)->field )

    7,按照LSB格式把两个字节转化为一个Word

    #define FLIPW( ray ) ( (((word) (ray)[0]) << 8) + (ray)[1] )

    8,按照LSB格式把一个Word转化为两个字节

    #define FLOPW( ray, val )

    (ray)[0] = ((val) / 256);

    (ray)[1] = ((val) & 0xFF)

    9,得到一个变量的地址(word宽度)

    #define B_PTR( var ) ( (byte *) (void *) &(var) )

    #define W_PTR( var ) ( (word *) (void *) &(var) )

    10,得到一个字的高位和低位字节

    #define WORD_LO(***) ((byte) ((word)(***) & 255))

    #define WORD_HI(***) ((byte) ((word)(***) >> 8))

    11,返回一个比X大的最接近的8的倍数

    #define RND8( x ) ((((x) + 7) / 8 ) * 8 )

    12,将一个字母转换为大写

    #define UPCASE( c ) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )

    13,判断字符是不是10进值的数字

    #define DECCHK( c ) ((c) >= '0' && (c) <= '9')

    14,判断字符是不是16进值的数字

    #define HEXCHK( c ) ( ((c) >= '0' && (c) <= '9') ||

    ((c) >= 'A' && (c) <= 'F') ||

    ((c) >= 'a' && (c) <= 'f') )

    15,防止溢出的一个方法

    #define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))

    16,返回数组元素的个数

    #define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )

    17,返回一个无符号数n尾的值MOD_BY_POWER_OF_TWO(X,n)=X%(2^n)

    #define MOD_BY_POWER_OF_TWO( val, mod_by )

    ( (dword)(val) & (dword)((mod_by)-1) )

    18,对于IO空间映射在存储空间的结构,输入输出处理

    #define inp(port) (*((volatile byte *) (port)))

    #define inpw(port) (*((volatile word *) (port)))

    #define inpdw(port) (*((volatile dword *)(port)))

    #define outp(port, val) (*((volatile byte *) (port)) = ((byte) (val)))

    #define outpw(port, val) (*((volatile word *) (port)) = ((word) (val)))

    #define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))

    19,使用一些宏跟踪调试

    A N S I标准说明了五个预定义的宏名。它们是:

    _ L I N E _

    _ F I L E _

    _ D A T E _

    _ T I M E _

    _ S T D C _

    如果编译不是标准的,则可能仅支持以上宏名中的几个,或根本不支持。记住编译程序

    也许还提供其它预定义的宏名。

    _ L I N E _及_ F I L E _宏指令在有关# l i n e的部分中已讨论,这里讨论其余的宏名。

    _ D AT E _宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。

    源代码翻译到目标代码的时间作为串包含在_ T I M E _中。串形式为时:分:秒。

    如果实现是标准的,则宏_ S T D C _含有十进制常量1。如果它含有任何其它数,则实现是

    非标准的。

    可以定义宏,例如:

    当定义了_DEBUG,输出数据信息和所在文件所在行

    #ifdef _DEBUG

    #define DEBUGMSG(msg,date) printf(msg);printf("%d%d%d",date,_LINE_,_FILE_)

    #else

    #define DEBUGMSG(msg,date)

    #endif

    20,宏定义防止使用是错误

    用小括号包含。

    例如:#define ADD(a,b) (a+b)

    用do{}while(0)语句包含多语句防止错误

    例如:#difne DO(a,b) a+b;

    a++;

    应用时:if(….)

    DO(a,b); //产生错误

    else

     

     

     

     

     

     

    1. static全局变量和普通的全局变量的区别?

      static全局变量只能初始化一次,防止在其他文件单元中被引用;

    2. static局部变量和普通的局部变量的区别?

    static局部变量只能初始化一次,下一次依据上一次的结果值

    1. static函数与普通函数的区别?

    static函数在内存中只有一份,普通函数在每次调用时维持一份拷贝。

     

     

    DSP、嵌入式、软件等

    1、请用方框图描述一个你熟悉的实用数字信号处理系统,并做简要的分析;如果没有,

    也可以自己设计一个简单的数字信号处理系统,并描述其功能及用途。(仕兰微面试题

    目)

    2、数字滤波器的分类和结构特点。(仕兰微面试题目)

    3、IIR,FIR滤波器的异同。(新太硬件面题)

    4、拉氏变换与Z变换公式等类似东西,随便翻翻书把如.h(n)=-a*h(n-1)+b*δ(n)  a.求h

    (n)的z变换;b.问该系统是否为稳定系统;c.写出FIR数字滤波器的差分方程;(未知)

    5、DSP和通用处理器在结构上有什么不同,请简要画出你熟悉的一种DSP结构图。(信威

    dsp软件面试题)

    6、说说定点DSP和浮点DSP的定义(或者说出他们的区别)(信威dsp软件面试题)

    7、说说你对循环寻址和位反序寻址的理解.(信威dsp软件面试题)

    8、请写出【-8,7】的二进制补码,和二进制偏置码。用Q15表示出0.5和-0.5.(信威

    dsp软件面试题)

    9、DSP的结构(哈佛结构);(未知)

    10、嵌入式处理器类型(如ARM),操作系统种类(Vxworks,ucos,winCE,linux),操作系

    统方面偏CS方向了,在CS篇里面讲了;(未知)

    11、有一个LDO芯片将用于对手机供电,需要你对他进行评估,你将如何设计你的测试项

    目?

    12、某程序在一个嵌入式系统(200M CPU,50M SDRAM)中已经最优化了,换到零一个系

    统(300M CPU,50M SDRAM)中是否还需要优化? (Intel) 

    13、请简要描述HUFFMAN编码的基本原理及其基本的实现方法。(仕兰微面试题目)

    14、说出OSI七层网络协议中的四层(任意四层)。(仕兰微面试题目)

    15、A)  (仕兰微面试题目)

      #i nclude  

      void testf(int*p)  

      {  

      *p+=1;  

      }  

      main()  

      {  

      int *n,m[2];  

      n=m;  

      m[0]=1;  

      m[1]=8;  

      testf(n);  

      printf("Data value is %d ",*n);  

      }  

      ------------------------------  

      B)  

      #i nclude  

      void testf(int**p)  

      {  

      *p+=1;  

      }  

      main()  

      {int *n,m[2];  

      n=m;  

      m[0]=1;  

      m[1]=8;  

      testf(&n);  

      printf(Data value is %d",*n);  

      }  

      下面的结果是程序A还是程序B的?  

      Data value is 8  

    那么另一段程序的结果是什么?  

     

     

     

    16、那种排序方法最快? (华为面试题)

    17、写出两个排序算法,问哪个好?(威盛)

    18、编一个简单的求n!的程序 。(Infineon笔试试题)

    19、用一种编程语言写n!的算法。(威盛VIA 2003.11.06 上海笔试试题)

    20、用C语言写一个递归算法求N!;(华为面试题) 

    21、给一个C的函数,关于字符串和数组,找出错误;(华为面试题) 

    22、防火墙是怎么实现的? (华为面试题)

    23、你对哪方面编程熟悉?(华为面试题)

    24、冒泡排序的原理。(新太硬件面题)

    25、操作系统的功能。(新太硬件面题)

    26、学过的计算机语言及开发的系统。(新太硬件面题)

    27、一个农夫发现围成正方形的围栏比长方形的节省4个木桩但是面积一样.羊的数目和正 方形围栏的桩子的个数一样但是小于36,问有多少羊?(威盛)

    28、C语言实现统计某个cell在某.v文件调用的次数(这个题目真bt) (威盛VIA 

    2003.11.06 上海笔试试题)

    29、用C语言写一段控制手机中马达振子的驱动程序。(威胜)

    30、用perl或TCL/Tk实现一段字符串识别和比较的程序。(未知)

    31、给出一个堆栈的结构,求中断后显示结果,主要是考堆栈压入返回地址存放在低端地 址还是高端。(未知)

    32、一些DOS命令,如显示文件,拷贝,删除。(未知)

    33、设计一个类,使得该类任何形式的派生类无论怎么定义和实现,都无法产生任何对象 实例。(IBM)

    34、What is pre-emption? (Intel)

    35、What is the state of a process if a resource is not available? (Intel)

    36、三个 float a,b,c;问值(a+b)+c==(b+a)+c, (a+b)+c==(a+c)+b。(Intel)  

    37、把一个链表反向填空。  (lucent)

    38、x^4+a*x^3+x^2+c*x+d 最少需要做几次乘法? (Dephi)

     

     

     

     

     主观题

    1、你认为你从事研发工作有哪些特点?(仕兰微面试题目)

    2、说出你的最大弱点及改进方法。(威盛VIA 2003.11.06 上海笔试试题)

    3、说出你的理想。说出你想达到的目标。 题目是英文出的,要用英文回答。(威盛VIA  2003.11.06 上海笔试试题)

    4、我们将研发人员分为若干研究方向,对协议和算法理解(主要应用在网络通信、图象语音压缩方面)、电子系统方案的研究、用MCU、DSP编程实现电路功能、用ASIC设计技术设计电路(包括MCU、DSP本身)、电路功能模块设计(包括模拟电路和数字电路)、集成电路后端设计(主要是指综合及自动布局布线技术)、集成电路设计与工艺接口的研究。

    你希望从事哪方面的研究?(可以选择多个方向。另外,已经从事过相关研发的人员可以详细描述你的研发经历)。(仕兰微面试题目)

    5、请谈谈对一个系统设计的总体思路。针对这个思路,你觉得应该具备哪些方面的知 识?(仕兰微面试题目)

    6、设想你将设计完成一个电子电路方案。请简述用EDA软件(如PROTEL)进行设计(包括 原理图和PCB图)到调试出样机的整个过程。在各环节应注意哪些问题?电源的稳定,电 容的选取,以及布局的大小。(汉王笔试)

     

     

     

     

     

    共同的注意点

    1.一般情况下,面试官主要根据你的简历提问,所以一定要对自己负责,把简历上的东西搞明白;

    2.个别招聘针对性特别强,就招目前他们确的方向的人,这种情况下,就要投其所好,尽 量介绍其所关心的东西。

    3.其实技术面试并不难,但是由于很多东西都忘掉了,才觉得有些难。所以最好在面试前 把该看的书看看。

    4.虽然说技术面试是实力的较量与体现,但是不可否认,由于不用面试官/公司所专领域 及爱好不同,也有面试也有很大的偶然性,需要冷静对待。不能因为被拒,就否认自己或 责骂公司。

    5.面试时要take it easy,对越是自己钟情的公司越要这样。

    微软亚洲技术支持中心面试题目

      1.进程和线程的差别。

      2.Heap与stack的差别。

      3.Windows下的内存是如何管理的?

      4.介绍.Net和.Net的安全性。

      5.客户端如何访问.Net组件实现Web Service?

      6.C/C++编译器中虚表是如何完成的?

      7.谈谈COM的线程模型。然后讨论进程内/外组件的差别。

      8.谈谈IA32下的分页机制。

      9.给两个变量,如何找出一个带环单链表中是什么地方出现环的?

      10.在IA32中一共有多少种办法从用户态跳到内核态?

      11.如果只想让程序有一个实例运行,不能运行两个。像winamp一样,只能开一个窗口,怎样实现?

      12.如何截取键盘的响应,让所有的'a'变成'b'?

      13.Apartment在COM中有什么用?为什么要引入?

      14.存储过程是什么?有什么用?有什么优点?

      15.Template有什么特点?什么时候用?

      16.谈谈Windows DNA结构的特点和优点。

      微软研究院笔试题目

      1.#include

      #include

      class CBuffer

      {

      char * m_pBuffer;

      int m_size;

      publc:

      CBuffer()

      {

      m_pBuffer=NULL;

      }

      ~CBuffer()

      {

      Free();

      }

      void Allocte(int size)

      {

      m_size=size;

      m_pBuffer= new char[size];

      }

      private:

      void Free()

      {

      if(m_pBuffer!=NULL)

      {

      delete m_pBuffer;

      m_pBuffer=NULL;

      }

      }

      public:

      void SaveString(const char* pText) const

      {

      strcpy(m_pBuffer, pText);

      char* GetBuffer() const

      {

      return m_pBuffer;

      }

      };

      void main (int argc, char* argv[])

      {

      cBuffer buffer1;

      buffer1.SaveString("Microsoft");

      printf(buffer1.GetBuffer());

      }

      }

    找出Allocate, SaveString, main的错误。

     

      2.打印"Welcome MSR Asia"

      #include

      #include

      char * GetName (void)

      {

      //To return "MSR Asia" String

      char name[]="MSR Asia";

      return name;

      }

      void main(int argc, char* argv[])

      {

      char name[32];

      //Fill in zeros into name

      for(int i=0;i<=32;i++)

      {

      name[1]='';

      }

      //copy "Welcome" to name

      name="Welcome";

      //Append a blank char

      name[8]=";

      //Append string to name

      strcat(name,GetName());

      //print out

      printf(name);

      }

      找出程序中的错误。

      3.#include

      class A

      {

      public:

      void FuncA()

      {

      printf("FuncA called ");

      }

      virtual void FuncB()

      {

      printf("FuncB called ");

      }

      };

      class B: public A

      {

      public:

      void FuncA()

      {

      A::FuncA();

      printf("FuncAB called ");

      }

      virtual void FuncB()

      {

      printf("FuncBB called ");

      }

      };

      void main(void)

      {

      B b;

      A *pa;

      pa=&b;

      A *pa2=new A;

      b.FuncA();

      b.FuncB();

      pa->FuncA();

      pa->FuncB();

      pa2->FuncA();

      pa2->FuncB();

      delete pa2;

      }

      What is the output of the above program?

      4.#include

      #include

      int FindSubString(char* pch)

      {

      int count=0;

      char* p1=pch;

      while(*p1!='')

      {

      if(*p1==p1[1]-1)

      {

      p1++;

      count++;

      }

      else

      {

      break;

      }

      }

      int count2=count;

      while(*p1!='')

      {

      if(*p1!==p1[1]+1)

      {

      p1++;

      count2--;

      }

      else

      {

      break;

      }

      if(count2==0)

      return count;

      return 0;

      }

      void ModifyString(char* pText)

      {

      char* p1=pText;

      char* p2=p1;

      while(*p1!='')

      {

      int count=FindSubString(p1);

      if(count>0)

      {

      *p2++=*p1;

      sprintf(p2, "%I", count);

      while(*p2!= '')

      {

      p2++;

      }

      p1+=count+count+1;

      }

      else

      {

      *p2++=*p1++;

      }

      }

      }

      void main(void)

      {

      char text[32]="XYBCDCBABABA";

      ModifyString(text);

      printf(text);

      }

      In the main() function, after ModifyString(text) is called, what's the value of 'text'?

     

     

     

     

     

     

     

    预处理器(Preprocessor)

    1 . 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

    #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL

    我在这想看到几件事情:

    1) #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)

    2)懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。

    3) 意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。

    4) 如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。

    2 . 写一个"标准"宏MIN ,这个宏输入两个参数并返回较小的一个。

    #define MIN(A,B) ((A) <= (B) ? (A) : (B))

    这个测试是为下面的目的而设的:

    1) 标识#define在宏中应用的基本知识。这是很重要的。因为在 嵌入(inline)操作符 变为标准C的一部分之前,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是必须的方法。

    2)三重条件操作符的知识。这个操作符存在C语言中的原因是它使得编译器能产生比if-then-else更优化的代码,了解这个用法是很重要的。

    3) 懂得在宏中小心地把参数用括号括起来

    4) 我也用这个问题开始讨论宏的副作用,例如:当你写下面的代码时会发生什么事?

    least = MIN(*p++, b);

     

     

    3. 预处理器标识#error的目的是什么?

    如果你不知道答案,请看参考文献1。这问题对区分一个正常的伙计和一个书呆子是很有用的。只有书呆子才会读C语言课本的附录去找出象这种问题的答案。当然如果你不是在找一个书呆子,那么应试者最好希望自己不要知道答案。

     

     

    死循环(Infinite loops)

    4. 嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢?

    这个问题用几个解决方案。我首选的方案是:

    while(1)

    {

    }

    一些程序员更喜欢如下方案:

    for(;;)

    {

    }

    这个实现方式让我为难,因为这个语法没有确切表达到底怎么回事。如果一个应试者给出这个作为方案,我将用这个作为一个机会去探究他们这样做的基本原理。如果他们的基本答案是:"我被教着这样做,但从没有想到过为什么。"这会给我留下一个坏印象。

    第三个方案是用 goto

    Loop:

    ...

    goto Loop;

    应试者如给出上面的方案,这说明或者他是一个汇编语言程序员(这也许是好事)或者他是一个想进入新领域的BASIC/FORTRAN程序员。

     

     

    数据声明(Data declarations)

    5. 用变量a给出下面的定义

    a) 一个整型数(An integer)

    b)一个指向整型数的指针( A pointer to an integer)

    c)一个指向指针的的指针,它指向的指针是指向一个整型数( A pointer to a pointer to an intege)r

    d)一个有10个整型数的数组( An array of 10 integers)

    e) 一个有10个指针的数组,该指针是指向一个整型数的。(An array of 10 pointers to integers)

    f) 一个指向有10个整型数数组的指针( A pointer to an array of 10 integers)

    g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer)

    h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argument and return an integer )

    答案是:

    a) int a; // An integer

    b) int *a; // A pointer to an integer

    c) int **a; // A pointer to a pointer to an integer

    d) int a[10]; // An array of 10 integers

    e) int *a[10]; // An array of 10 pointers to integers

    f) int (*a)[10]; // A pointer to an array of 10 integers

    g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer

    h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer

    人们经常声称这里有几个问题是那种要翻一下书才能回答的问题,我同意这种说法。当我写这篇文章时,为了确定语法的正确性,我的确查了一下书。但是当我被面试的时候,我期望被问到这个问题(或者相近的问题)。因为在被面试的这段时间里,我确定我知道这个问题的答案。应试者如果不知道所有的答案(或至少大部分答案),那么也就没有为这次面试做准备,如果该面试者没有为这次面试做准备,那么他又能为什么出准备呢?

    Static

    6. 关键字static的作用是什么?

    这个简单的问题很少有人能回答完全。在C语言中,关键字static有三个明显的作用:

    1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。

    2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。

    3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。

    大多数应试者能正确回答第一部分,一部分能正确回答第二部分,同是很少的人能懂得第三部分。这是一个应试者的严重的缺点,因为他显然不懂得本地化数据和代码范围的好处和重要性。

     

    Const

    7.关键字const有什么含意?

    我只要一听到被面试者说:"const意味着常数",我就知道我正在和一个业余者打交道。去年Dan Saks已经在他的文章里完全概括了const的所有用法,因此ESP(译者:Embedded Systems Programming)的每一位读者应该非常熟悉const能做什么和不能做什么.如果你从没有读到那篇文章,只要能说出const意味着"只读"就可以了。尽管这个答案不是完全的答案,但我接受它作为一个正确的答案。(如果你想知道更详细的答案,仔细读一下Saks的文章吧。)

    如果应试者能正确回答这个问题,我将问他一个附加的问题:

    下面的声明都是什么意思?

    const int a;

    int const a;

    const int *a;

    int * const a;

    int const * a const;

    /******/

    前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字 const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由:

    1) 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。)

    2) 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。

    3) 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。

     

     

    Volatile

    8. 关键字volatile有什么含意?并给出三个不同的例子。

    一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:

    1) 并行设备的硬件寄存器(如:状态寄存器)

    2) 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

    3) 多线程应用中被几个任务共享的变量

    回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。搞嵌入式的家伙们经常同硬件、中断、RTOS等等打交道,所有这些都要求用到volatile变量。不懂得volatile的内容将会带来灾难。

    假设被面试者正确地回答了这是问题(嗯,怀疑是否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。

    1)一个参数既可以是const还可以是volatile吗?解释为什么。

    2); 一个指针可以是volatile 吗?解释为什么。

    3); 下面的函数有什么错误:

    int square(volatile int *ptr)

    {

    return *ptr * *ptr;

    }

    下面是答案:

    1)是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。

    2); 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。

    3) 这段代码有点变态。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:

    int square(volatile int *ptr)

    {

    int a,b;

    a = *ptr;

    b = *ptr;

    return a * b;

    }

    由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:

    long square(volatile int *ptr)

    {

    int a;

    a = *ptr;

    return a * a;

    }

     

     

    位操作(Bit manipulation)

    9. 嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变。

    对这个问题有三种基本的反应

    1)不知道如何下手。该被面者从没做过任何嵌入式系统的工作。

    2) 用bit fields。Bit fields是被扔到C语言死角的东西,它保证你的代码在不同编译器之间是不可移植的,同时也保证了的你的代码是不可重用的。我最近不幸看到 Infineon为其较复杂的通信芯片写的驱动程序,它用到了bit fields因此完全对我无用,因为我的编译器用其它的方式来实现bit fields的。从道德讲:永远不要让一个非嵌入式的家伙粘实际硬件的边。

    3) 用 #defines 和 bit masks 操作。这是一个有极高可移植性的方法,是应该被用到的方法。最佳的解决方案如下:

    #define BIT3 (0x1 << 3)

    static int a;

    void set_bit3(void)

    {

    a |= BIT3;

    }

    void clear_bit3(void)

    {

    a &= ~BIT3;

    }

    一些人喜欢为设置和清除值而定义一个掩码同时定义一些说明常数,这也是可以接受的。我希望看到几个要点:说明常数、|=和&=~操作。

     

     

    访问固定的内存位置(Accessing fixed memory locations)

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

    这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针是合法的。这一问题的实现方式随着个人风格不同而不同。典型的类似代码如下:

    int *ptr;

    ptr = (int *)0x67a9;

    *ptr = 0xaa55;

    A more obscure approach is:

    一个较晦涩的方法是:

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

    即使你的品味更接近第二种方案,但我建议你在面试时使用第一种方案。

     

     

    中断(Interrupts)

    11. 中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字 __interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。

    __interrupt double compute_area (double radius)

    {

    double area = PI * radius * radius;

    printf(" Area = %f", area);

    return area;

    }

    这个函数有太多的错误了,以至让人不知从何说起了:

    1)ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。

    2) ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。

    3) 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。

    4). 与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了。

     

     

    代码例子(Code examples)

    12 . 下面的代码输出是什么,为什么?

    void foo(void)

    {

    unsigned int a = 6;

    int b = -20;

    (a+b > 6) puts("> 6") : puts("<= 6");

    }

    这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是">6"。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。 因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。

     

    13. 评价下面的代码片断:

    unsigned int zero = 0;

    unsigned int compzero = 0xFFFF;

    /*1's complement of zero */

    对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写如下:

    unsigned int compzero = ~0;

    这一问题真正能揭露出应试者是否懂得处理器字长的重要性。在我的经验里,好的嵌入式程序员非常准确地明白硬件的细节和它的局限,然而PC机程序往往把硬件作为一个无法避免的烦恼。

    到了这个阶段,应试者或者完全垂头丧气了或者信心满满志在必得。如果显然应试者不是很好,那么这个测试就在这里结束了。但如果显然应试者做得不错,那么我就扔出下面的追加问题,这些问题是比较难的,我想仅仅非常优秀的应试者能做得不错。提出这些问题,我希望更多看到应试者应付问题的方法,而不是答案。不管如何,你就当是这个娱乐吧…

     

     

    动态内存分配(Dynamic memory allocation)

    14. 尽管不像非嵌入式计算机那么常见,嵌入式系统还是有从堆(heap)中动态分配内存的过程的。那么嵌入式系统中,动态分配内存可能发生的问题是什么?

    这里,我期望应试者能提到内存碎片,碎片收集的问题,变量的持行时间等等。这个主题已经在ESP杂志中被广泛地讨论过了(主要是 P.J. Plauger, 他的解释远远超过我这里能提到的任何解释),所有回过头看一下这些杂志吧!让应试者进入一种虚假的安全感觉后,我拿出这么一个小节目:下面的代码片段的输出是什么,为什么?

    char *ptr;

    if ((ptr = (char *)malloc(0)) == NULL)

    puts("Got a null pointer");

    else

    puts("Got a valid pointer");

    这是一个有趣的问题。最近在我的一个同事不经意把0值传给了函数malloc,得到了一个合法的指针之后,我才想到这个问题。这就是上面的代码,该代码的输出是"Got a valid pointer"。我用这个来开始讨论这样的一问题,看看被面试者是否想到库例程这样做是正确。得到正确的答案固然重要,但解决问题的方法和你做决定的基本原理更重要些。

     

     

    Typedef

    15. Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。例如,思考一下下面的例子:

    #define dPS struct s *

    typedef struct s * tPS;

    以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么?

    这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被恭喜的。答案是:typedef更好。思考下面的例子:

    dPS p1,p2;

    tPS p3,p4;

    第一个扩展为

    struct s * p1, p2;

    上面的代码定义p1为一个指向结构的指,p2为一个实际的结构,这也许不是你想要的。第二个例子正确地定义了p3 和p4 两个指针。

     

     

    晦涩的语法

    16. C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?

    int a = 5, b = 7, c;

    c = a+++b;

    这个问题将做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子是完全合乎语法的。问题是编译器如何处理它?水平不高的编译作者实际上会争论这个问题,根据最处理原则,编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处理成:

    c = a++ + b;

    因此, 这段代码持行后a = 6, b = 7, c = 12。

    如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不把这个当作问题。我发现这个问题的最大好处是:这是一个关于代码编写风格,代码的可读性,代码的可修改性的好的话题

     

     

     

     

     

    常见嵌入式笔试题(一)

    1)将一个字符串逆序

     代码:

    #include<stdio.h>

    #include<string.h>

    void s_back(char * a )

    {

    int i=0;

    char temp =0;

    char * ps;

    char * pe;

    if(!a)

    return;

    ps=a;

    while(*a!=0)

    a++;

    pe=a;

    for(i=0;i<(pe-ps)/2;i++)     

    {

    temp=*(ps+i);

    *(ps+i)=*(pe-i-1);

    *(pe-i-1)=temp;

    }

    }

    int main()

    {

    char * a=(char *)malloc(100);

    memcpy(a,"a123456789",11);

    printf("%s ",a);

    s_back(a);

    printf("%s ",a);

    free(a);

    return 0;

    }

     

     

    2)计算一个字节(byte)里有多少为(bit)被置1。

     1)code:

    #include<stdio.h>

    int b_check(char x)

    {

    int i=0;

    int count=0;

    for(i=0;i<8;i++)

    {

    if(1==((x>>i)&1))

    count++;

    }

    return count;

    }

    int main()

    {

    int x=0xff;

    printf("%d ",b_check(x));

    return 0;

    }

     

     

     

     

     

    #ifdef _MSC_VER

    #pragma function(strcmp)

    #endif /* _MSC_VER */

     

    /***

    *strcmp - compare two strings, returning less than, equal to, or greater than

    *

    *Purpose:

    * STRCMP compares two strings and returns an integer

    * to indicate whether the first is less than the second, the two are

    * equal, or whether the first is greater than the second.

    *

    * Comparison is done byte by byte on an UNSIGNED basis, which is to

    * say that Null (0) is less than any other character (1-255).

    **Entry:

    * const char * src - string for left-hand side of comparison

    * const char * dst - string for right-hand side of comparison

    **Exit:

    * returns -1 if src < dst

    * returns 0 if src == dst

    * returns +1 if src > dst

    **Exceptions:

    ********************************************************************************/

    int __cdecl strcmp (

    const char * src,

    const char * dst

    )

    {

    int ret = 0 ;

    while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)

    ++src, ++dst;

    if ( ret < 0 )

    ret = -1 ;

    else if ( ret > 0 )

    ret = 1 ;

    return( ret );

    }

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

          进程和线程的区别

     分析问题

    1.进程的概念

    简单来说,进程代表了操作系统上运行着的一个应用程序。进程拥有自己的程序块,拥有独占的资源和数据,并且可被操作系统来调度。即使同一个应用程序,当被强制多次启动时,也会被安放到不同的进程之中单独运行。直观地理解进程最好的方式就是通过进程管理器浏览一下当前计算机正在运行的进程,进程浏览器中的每条记录都代表了一个活动着的进程,如图7.1所示。

    并不是每个进程都会在Windows自带的进程浏览器中显示的,详细原因不属于本书的覆盖范围,有兴趣的读者可以自行参考微软公司操作系统的产品文档。

    2.线程的概念

    线程有时候也被称为微进程或者轻量级进程,它的概念和进程十分相似,是一个可以被调度的单元,并且维护自己的堆栈和上下文环境。线程是附属于进程的,一个进程可以包含1个或者多个线程,并且同一进程内的多个线程共享一块内存块和资源。一个线程是一个操作系统可调度的基本单元,但同时它的调度受限于包含该线程的进程,也就是说操作系统首先决定下一个执行的进程,进而才会调度该进程内的线程。

    3.线程和进程的区别

    线程和进程最大的区别在于隔离性问题。每个进程都被单独地隔离,拥有自己的内存块、独占的资源及运行数据,一个进程的崩溃不会影响到其他进程,而进程间的交互也是相当困难的。和进程不同,同一进程内的所有线程共享资源和内存块,并且一个线程可以访问、结束同一进程内的其他线程。

     答案

    简单来说进程代表了一个正在运行的应用程序的实体,而一个进程中可包含1个或者多个线程。关于详细的概念请参考本节的分析问题。

    7.1.2  多线程程序在操作系统里是并行执行的吗

    编写多线程的程序,大部分情况下是希望得到并行处理带来的高效率。那在操作系统层面上多个线程的运行是否真的是并行运行的呢?这样的问题在.NET面试中也时常会出现,旨在考查应聘者关于操作系统中线程调度的基本知识。

     所涉及的知识点

    ·      线程调度的概念

    ·      多处理器系统的特点

     分析问题

    1.线程调度

    回顾计算机系统发展的历史,在早期的操作系统之上,应用程序的执行完全不存在并行的概念。所有的应用都排队等候在一个单线程的队列之中,每个程序都必须等到前面的程序都安全地执行完毕后才能获得执行的权利,一个小的错误将会导致操作系统上所有程序的阻塞。在后来的操作系统中,逐渐产生了分时和进程、线程的概念。

    多个线程受到操作系统的调度控制,以决定何时运行哪个线程。所谓的线程调度,是指操作系统决定如何安排线程执行顺序的算法。按照常规的分类,线程调度可分为抢占式调度和非抢占式调度两种方法。

    1)抢占式调度

    抢占式调度是指每个线程都只有极少的运行时间(在Windows NT内核模式下这个时间不会超过20ms),而当时间用完时该线程就会被强制暂停,保存上下文并把运行权利交给下一个线程,这样调度的结果就是所有的线程都在被快速地切换运行,使得使用者感觉所有的线程在并行运行。

    2)非抢占式调度

    非抢占式调度是指某个线程在运行时不会被操作系统强制暂停,它可以持续地运行直至运行告一段落并主动地交出运行权。在这样的调度模式之下,线程的运行就完全是单队列的,并且可能产生恶意程序长期霸占运行权的情况。

    现在很多的操作系统,包括微软公司的Windows系统,都同时采用抢占式和非抢占式模式。对于那些优先级相当高的线程,操作系统采用非抢占式来给予充分的时间运行,而对于普通的线程,则采用抢占式模式来快速地切换执行。

    2.线程的并行问题

    在单CPU单核的系统架构之上,线程的并行运行完全是使用者的主观体验,事实上在任一时刻只可能存在一个处于运行状态的线程。但在多CPU或多核的架构上,情况则略有不同。多CPU多核的架构允许操作系统完全并行地运行两个或多个无其他资源争用的线程,理论上这样的架构可以使运行性能整数倍地提高。

    微软公司曾经提出过超线程的技术,简单来说这是一种逻辑上模拟多CPU的技术,但实际上它们却共享物理处理器和缓存。超线程对性能的提高相当有限。

     答案

    在单CPU的计算机架构上,任何时候只可能存在一个运行的线程,操作系统通过快速的调度轮换使使用者感觉到多线程在同时执行。而在多CPU的架构上,则可能存在完全并行运行的线程,这取决于线程之间是否争用了其他的资源

     

     

     

     

     

     

    1、进程和线程的区别

    进程是系统进行资源分配和调度的单位;线程是CPU调度和分派的单位,一个进程可以有多个线程,这些线程共享这个进程的资源。

    2、成员变量和成员函数前加static的作用

    它们被称为常成员变量和常成员函数,又称为类成员变量和类成员函数。分别用来反映类的状态。比如类成员变量可以用来统计类实例的数量,类成员函数负责这种统计的动作。

    3、malloc和new的区别

    new是C++的关键字。malloc在分配内存时必须按给出的字节分配,new可以按照对象的大小自动分配,并且能调用构造函数。可以说new是对象的对象,而malloc不是。本质上new分配内存时,还会在实际内存块的前后加上附加信息,所以new所使用的内存大小比malloc多。

    4、堆和栈的区别

    栈:由编译器自动分配、释放。在函数体中定义的变量通常在栈上。

    堆:一般由程序员分配释放。用new、malloc等分配内存函数分配得到的就是在堆上。

    栈是机器系统提供的数据结构,而堆则是C/C++函数库提供的。

    栈是系统提供的功能,特点是快速高效,缺点是有限制,数据不灵活;而栈是函数库提供的功能,特点是灵活方便,数据适应面广泛,但是效率有一定降低。栈是系统数据结构,对于进程/线程是唯一的;堆是函数库内部数据结构,不一定唯一。不同堆分配的内存无法互相操作。栈空间分静态分配和动态分配两种。静态分配是编译器完成的,比如自动变量(auto)的分配。动态分配由alloca函数完成。栈的动态分配无需释放(是自动的),也就没有释放函数。为可移植的程序起见,栈的动态分配操作是不被鼓励的!堆空间的分配总是动态的,虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存/释放内存匹配是良好程序的基本要素。

     

     

     

     

    1. C#中 property 与 attribute的区别,他们各有什么用处,这种机制的好处在哪里?

    2. 讲一讲你理解的web service,在dot net framework中,怎么很好的结合xml?(讲概念就行了)

    3. C#, Java 和 c++的特点,有什么相同的地方,不同的地方,C#分别从c++和java中吸取了他们那些优点?

    4. C#可否对内存进行直接的操作?(这可是个难点哦?要注意!)

    5. 用Visual C++ 6.0编写的代码(unmanaged code),如何在CLR下和其他dot net component结合?

    6. 以前作过的一些项目?介绍一下自己的编程经验。(这是蒙混不过去的,基本一问就知道是真是假)

    7. 你对公司有什么期望?你的薪水期望值?为什么学计算机?以前的工作经验(这非常重要)?

     

    Q3: 维护数据库的完整性、一致性、你喜欢用触发器还是自写业务逻辑?为什么

    Q4:ADO。NET相对于ADO等主要有什么改进?

    Q5:ASP。NET与ASP相比,主要有哪些进步?

    Q6:C#中的委托是什么?事件是不是一种委托?

    Q7:描述一下C#中索引器的实现过程,是否只能根据数字进行索引?

    Q8:C#中要使一个类支持FOREACH遍历,实现过程怎样?

    Q10:写一个HTML页面,实现以下功能,左键点击页面时显示"您好",右键点击时显示"禁止右键"。并在2分钟后自动关闭页面。

    Q11:你对XMLHTTP、WEBSERVICE 了解吗?简单描述其特点、作用

    Q12:接口和抽象类有什么区别?你选择使用接口和抽象类的依据是什么?

    Q13:自定义控件和一般用户控件的异同?如果要用这两者之一,你会选择哪种?为什么

    Q14:大概描述一下ASP。NET服务器控件的生命周期

    Q15:UML

    Q16:面向对象的概念,主要特点

    Q17:类划分的依据。类粒度问题

    Q18:事物管理问题

     

    第一,谈谈final, finally, finalize的区别。

    第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?

    第三,Static Nested Class 和 Inner Class的不同,说得越多越好(面试题有的很笼统)。

    第四,&和&&的区别。

    第五,HashMap和Hashtable的区别。

    第六,Collection 和 Collections的区别。

    第七,什么时候用assert。

    第八,GC是什么? 为什么要有GC?

    第九,String s = new String("xyz");创建了几个String Object?

    第十,Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

    第十一,short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?

    第十二,sleep() 和 wait() 有什么区别?

    第十三,Java有没有goto?

    第十四,数组有没有length()这个方法? String有没有length()这个方法?

    第十五,Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?

    第十六,Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?

    第十七,给我一个你最常见到的runtime exception。

    第十八,error和exception有什么区别?

    第十九,List, Set, Map是否继承自Collection接口?

    第二十,abstract class和interface有什么区别?

    第二十一,abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?

    第二十二,接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?

    第二十三,启动一个线程是用run()还是start()?

    第二十四,构造器Constructor是否可被override?

    第二十五,是否可以继承String类?

    第二十六,当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?

    第二十七,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?

    第二十八,编程题: 用最有效率的方法算出2乘以8等於几?

    第二十九,两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?

    第三十,当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

    第三十一,swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?

    第三十二,编程题: 写一个Singleton出来。

     

    1、进程和线程的区别

    进程是系统进行资源分配和调度的单位;线程是CPU调度和分派的单位,一个进程可以有多个线程,这些线程共享这个进程的资源。

    2、成员变量和成员函数前加static的作用

    它们被称为常成员变量和常成员函数,又称为类成员变量和类成员函数。分别用来反映类的状态。比如类成员变量可以用来统计类实例的数量,类成员函数负责这种统计的动作。

    3、malloc和new的区别

    new是C++的关键字。malloc在分配内存时必须按给出的字节分配,new可以按照对象的大小自动分配,并且能调用构造函数。可以说new是对象的对象,而malloc不是。本质上new分配内存时,还会在实际内存块的前后加上附加信息,所以new所使用的内存大小比malloc多。

    4、堆和栈的区别

    栈:由编译器自动分配、释放。在函数体中定义的变量通常在栈上。

    堆:一般由程序员分配释放。用new、malloc等分配内存函数分配得到的就是在堆上。

    栈是机器系统提供的数据结构,而堆则是C/C++函数库提供的。

    栈是系统提供的功能,特点是快速高效,缺点是有限制,数据不灵活;而栈是函数库提供的功能,特点是灵活方便,数据适应面广泛,但是效率有一定降低。栈是系统数据结构,对于进程/线程是唯一的;堆是函数库内部数据结构,不一定唯一。不同堆分配的内存无法互相操作。栈空间分静态分配和动态分配两种。静态分配是编译器完成的,比如自动变量(auto)的分配。动态分配由alloca函数完成。栈的动态分配无需释放(是自动的),也就没有释放函数。为可移植的程序起见,栈的动态分配操作是不被鼓励的!堆空间的分配总是动态的,虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存/释放内存匹配是良好程序的基本要素。

    5、不调用C++/C的字符串库函数,请编写函数 strcpy

     

    1. C#中 property 与 attribute的区别,他们各有什么用处,这种机制的好处在哪里?

    2. 讲一讲你理解的web service,在dot net framework中,怎么很好的结合xml?(讲概念就行了)

    3. C#, Java 和 c++的特点,有什么相同的地方,不同的地方,C#分别从c++和java中吸取了他们那些优点?

    4. C#可否对内存进行直接的操作?(这可是个难点哦?要注意!)

    5. 用Visual C++ 6.0编写的代码(unmanaged code),如何在CLR下和其他dot net component结合?

    6. 以前作过的一些项目?介绍一下自己的编程经验。(这是蒙混不过去的,基本一问就知道是真是假)

    7. 你对公司有什么期望?你的薪水期望值?为什么学计算机?以前的工作经验(这非常重要)?

     

    Q3: 维护数据库的完整性、一致性、你喜欢用触发器还是自写业务逻辑?为什么

    Q4:ADO。NET相对于ADO等主要有什么改进?

    Q5:ASP。NET与ASP相比,主要有哪些进步?

    Q6:C#中的委托是什么?事件是不是一种委托?

    Q7:描述一下C#中索引器的实现过程,是否只能根据数字进行索引?

    Q8:C#中要使一个类支持FOREACH遍历,实现过程怎样?

    Q10:写一个HTML页面,实现以下功能,左键点击页面时显示"您好",右键点击时显示"禁止右键"。并在2分钟后自动关闭页面。

    Q11:你对XMLHTTP、WEBSERVICE 了解吗?简单描述其特点、作用

    Q12:接口和抽象类有什么区别?你选择使用接口和抽象类的依据是什么?

    Q13:自定义控件和一般用户控件的异同?如果要用这两者之一,你会选择哪种?为什么

    Q14:大概描述一下ASP。NET服务器控件的生命周期

    Q15:UML

    Q16:面向对象的概念,主要特点

    Q17:类划分的依据。类粒度问题

    Q18:事物管理问题

     

    第一,谈谈final, finally, finalize的区别。

    第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?

    第三,Static Nested Class 和 Inner Class的不同,说得越多越好(面试题有的很笼统)。

    第四,&和&&的区别。

    第五,HashMap和Hashtable的区别。

    第六,Collection 和 Collections的区别。

    第七,什么时候用assert。

    第八,GC是什么? 为什么要有GC?

    第九,String s = new String("xyz");创建了几个String Object?

    第十,Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

    第十一,short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?

    第十二,sleep() 和 wait() 有什么区别?

    第十三,Java有没有goto?

    第十四,数组有没有length()这个方法? String有没有length()这个方法?

    第十五,Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?

    第十六,Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?

    第十七,给我一个你最常见到的runtime exception。

    第十八,error和exception有什么区别?

    第十九,List, Set, Map是否继承自Collection接口?

    第二十,abstract class和interface有什么区别?

    第二十一,abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?

    第二十二,接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?

    第二十三,启动一个线程是用run()还是start()?

    第二十四,构造器Constructor是否可被override?

    第二十五,是否可以继承String类?

    第二十六,当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?

    第二十七,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?

    第二十八,编程题: 用最有效率的方法算出2乘以8等於几?

    第二十九,两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?

    第三十,当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

    第三十一,swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?

    第三十二,编程题: 写一个Singleton出来。

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    将同一个应用程序同时作为 http 和 https
    将数组元素划分为等长的块(二维数组)
    将数组中的空元素转为 undefined
    将某个类型断言为另一个与之毫无关系的类型
    将前端代码放入 Egg 项目中
    将根组件挂载到 DOM 节点上
    将类数组对象转换成数组
    将 ts 代码转成 js 代码
    将代码推迟到系统资源空闲时执行
    React 将 state 传给子组件用
  • 原文地址:https://www.cnblogs.com/timssd/p/4107291.html
Copyright © 2020-2023  润新知