一家外企的笔试题

1、windows 下socket 编程,最高效的I/o模型是那个:

  选Completion port. (完成端口)

  不选overrapped, select等。

 

2、如何export dll的方法,四个中错误的是:

1 Export from a DLL Using .DEF Files

  2 Export from a DLL using __declspec(dllexport)

  3 对于c函数,使用 extern c{...}

那么,除了这三个外的那个选项就是错误的: 好像是在project 中设置/Export. 就记住“/Export”这个吧。

 

3、start service的函数调用顺序:

1 OpenSCManager //打开SC管理器

2 OpenService       //打开 service,

3 QueryServiceStatusEx //查询service的状态,是否是停止,如停止则可调下一步,启动

 4 StartService   //

 

4、calloc 和 malloc的区别

calloc 和 malloc都是从heap分配内存。

但calloc将内存数据初始化为0;

所以,calloc()适合分配小的内存。

c++ 库的new 默认是使用malloc的

note:calloc将内存数据初始化为0

下面是网上找的英文答案

There are two differences. First, is in the number of arguments. Malloc() takes a single argument (memory required in bytes), while calloc() needs two arguments (number of variables to allocate memory, size in bytes of a single variable). Secondly, malloc() does not initialize the memory allocated, while calloc() initializes the allocated memory to ZERO.

 

5、创建一个thread,可以带security 信息的函数是:

答案:  _beginThreadEx

 

6、查看message传递的工具

多选答: DDE spy++ and spy++

单选:截获process间的message就选DDESpy++,

如单单是窗口消息,则选 spy++

我查了一下,DDE spy 和spy++都可以查看message,但有些区别,spy++还可以看窗口,类型等。

 

7、查看 DLL export 函数的工具

Depends 和 dumpbin

 

8、用那个函数(方法)来退出线程:

答:TerminatedThread 肯定不对,TerminatedThread是很野蛮的退出,没有清理工作。

  在ExitThread 和_endthread中选择,如是多选,就多选。

  如是单选,注意问题中提到了使用_beginthread创建的thread吗,如提到了,就选_endthread。

  如是用CreateThread创建的thread,或没提如何创建的,就选ExitThread。

 

  实际上,在c++编程,正常来讲,应让thread函数自己正常返回(这样才能调用destructor函数),不必调用ExitThread或 _endthread(这两个好像不会调destructor函数,所以会可能泄露内存)。

这是个选择题,不要选TerminatedThread

 

9、Sleep(0) ,的效果是什么?

定义如下:

DWORD WINAPI SleepEx(

  __in  DWORD dwMilliseconds,

  __in  BOOL bAlertable

);

对于参数dwMilliseconds,MSDN的解释:

A value of zero causes the thread to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run. If there are no other threads of equal priority ready to run, the function returns immediately, and the thread continues execution.

 

我的理解:

填0,会让os重新调度线程的运行,这样其他同级别的ready线程可以运行,而此线程会处于ready状态,如果没有同级别的线程处于ready状态,则此函数立刻返回,当前线程继续运行。

 

对于第二个参数,你可以不理,估计有个默认值。

要明白一个thread有那些状态: running, ready ,wait, exiting, died

running:正在运行,占用cpu

ready:符合运行条件,就等其他thread让出cpu

wait: 不符合运行条件

 

10、how to send message to no-GUI thread

postmessage , sendmessage都是往一个窗口发消息的

解释一下:thread本没有gui-thread, nogui-thread的概念。

但windows把带处理窗口message队列的thread叫gui-thread

nogui-thread也叫工作线程,就像我们写的没有界面的线程。

postmessage , sendmessage都是往一个窗口发消息的,他们的第一个参数是一个HWND,即窗口handle,显然,这两个不行。

postThreadMessage 可以,他的第一个参数是 thread handle.

四个选择:postmessage , sendmessage, postThreadMessage,另一个忘了。我就选postThreadMessage

 

11、不能被重载的操作符有:

       :: 和 .  和 *. 和 ? 和 :

      答: .(点)不能被重载

      例如:

          class T a;

             a.fun();

             a.m_name;

       如(点)能被重载, 那这程序没法看了。

12、WaitForMultipleObjects的返回值为WAIT_ABANDONED时,说明什么情况发生?

答:一个拥有mutex的线程没放mutex,就退出了

 

13、调用哪个重载函数?

Print。

14、 Event Viewer可以查看的事件(类型)可来自下面那些?

选项1,2,3,4 共包含4个,无非是组合。选含四个的: 选择包含全部的。我能肯定有的是security。 回想起来,这道题考得是事件有哪些类型还是事件源有哪些,我是按事件源答的,所以全选。 参考 event viewer help,event viewer,打开:控制面板->性能和维护->管理工具—>事件查看器。

 

15__cdecl与 __stdcall区别

答: 1、__stdcall调用约定:函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈, 2、_cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。两个函数都是采用从右到左的压栈方式。注意:对于可变参数的成员函数,始终使用__cdecl的转换方式。

区别:__cdecl由调用者来处理参数的入栈,和出栈。

调用c函数,编译器也会生出一些代码,来处理参数的

在调用函数前,需将参数存入stack,调用后需,将参数从stack弹出。

这个代码,不用程序员写,编译器自动加上去。

但这个入stack,出stack的代码放在哪里? __cdecl就是放着调用函数的地方,所以,调用函数10次,这个入stack,出stack的代码就会有10次,调用100次,这个代码就重复100次,就像是inline.

__stdcall则是放在函数的开头(入stack)和尾部(出stack),这样,不管你调用函数多少次,入stack,出stack的代码就一份,所以__stdcall编译的程序小。但同时,__stdcall就不能处理变参数的函数,如printf。因为,只有调用函数的,才知道到底有几个参数。

 

16、程序输出?

class D

{

public:

void print(int i)

{

 printf("out int:%d",i);

 }

 void print(char c)

{

printf("out char:%c",c);

}

 };

class B: public D

{

 public:

 void print(char* s)

{

 printf("out string:%s", s);

}

}

main()

{

B b; b.print(1);

 b.print('A');

b.print("hello");

 }

答:1Ahello

 

17、如何避免 implicit 构造

class A { public: A(int i) {...}; ... } main() { A a = 0; }如何避免 A a = 0;

答:加explicit。A a = 0 包含两步:1 编译器构造一个temp A object(0)2 把这个object 赋值给a就是调用了赋值拷贝: operator=,加explicit就是避免第一步

 

18、以下两个构造有什么区别:

class A

{

public:

A::A():S("hello") { }

A:A()

{

 s = "hello";

 }

private string s;

}

answer:

1 initiate list, it has better performance than the latter.

2 s = "hello" , it shall generate a temp value.

 

19、输出结果是?

class noVirtualBase { public: noVirtualBase() { cout << "noVirtualBase" << endl; } }; class VirtualBase { public: VirtualBase() { cout << "VirtualBase" << endl; } }; class Derived: public noVirtualBase, virtual VirtualBase { public: Derived() { cout << "Derived" << endl; } }; int main() { Derived d; return 0; }

输出结果:VirtualBase noVirtualBase Derived

原则就是,先virtual base class, 在非virtual,然后是子类

 

20、void foo(char* s) { cout << sizeof(s) << endl; } int main() { char buf[] = "hello"; cout << sizeof(buf) << endl; foo((char*)buf); } 问输出是什么? 考点是char数组的size是多少,char* 的size是多少

答:6,4

 

21、输出结果是?

void fun1 (int& a, int b)

{

 cout << ( ++a+b--) << endl;

}

int main()

{

 int i = 1, j = 1;

fun1(i, j);

cout << i++ << "," << j << endl;

}

答:32,1

 

22、关于map的iterator 的操作

map values; map<*>::iterator ite; ite = values->end() -1

答:ite = values->end() -1,是错误写法。不能编译。对于map, map,第一个参数是关键字,用了index,所以不能改变map中的key,因为他觉得了存储的位置。总之,看到values->end() -1,它就是错的

 

23、typedef char(parray)[2][2];

答:parray* pp = new parray[10];

 

24、UDP编程用哪四个函数

1 listen 2 accept 3 socket 4 sendto 5 recvfrom 6 send 7 receive 8 shutdown 9 close

答:3459。67是TCP的。

 

25、tcp server的使用流程,用那些API

1 //create a socket

2 //bind a socket

3 //listen on a socket

4 //accept a connection 循环调用

5 close

 

26、inline?

  是否inline由compile来决定的,对于复杂的成员函数,即使inline修饰,compiler未必将其实现为inline。

 

27、public, protect, private 访问范围

 注意: friend class and friend function.

 

28、new和delete的用法错误的是

答:会多维数组的new,delete.

要特别注意多维数组的指针了,考c题,就会玩指针,函数指针,多维数组的指针。

 

29、listen(选择题,挑错)

答:listen这个不会阻塞的。

 

30、accept?

答:accept如是阻塞的,就会一直等,直到一个连接到。

tcp 是保证数据传送不丢失,不乱序,udp,这两点都不保证,udp只保证一个udp包是完整的。

31、输出是什么?

int main()

 

{

 

   int* p = 0x00000000;   // pointer to NULL

 

   puts("hello");

 

   __try{

 

      puts("in try");

 

      __try{

 

         puts("in try");

 

         *p = 13;    // causes an access violation exception;

 

      }__finally{

 

         puts("in finally. termination: ");

 

         puts(AbnormalTermination() ? "/tabnormal" : "/tnormal");

 

      }

 

   }__except(1){

 

      puts("in except");

 

   }

 

   puts("world");

 

}

 

答:http://msdn.microsoft.com/en-us/library/s58ftw19(VS.80).aspx

32、大小端

http://dev.csdn.net/article/60/60401.shtm

 

简答题1

 

static int g_count;

void thread_common_function()

{

       g_count++;

}

 

 

1 thread_common_function在多个thread同时运行,如何修改 thread_common_function(),保证thread safe.

 

答: At windows, usually, we can use these techniques to sync thread operation:

       

        Interlocked function

        Critical Section

        Mutex

        Binary Semaphore

       

    In this example, 只有一个++操作,所以用Interlocked function中的:

              InterlockedExchangeAdd

     是效率最好的。

        

代码改为:

void thread_common_function()

{

       InterlockedExchangeAdd(&g_count, 1);//

}

注意: 当然,可以直接答上面的代码,但如能说明为什么选择Interlocked function,而不是Critical Section,或Mutex则更好。

    关于thread同步技术的题,选择题有好几个那,所以必须明白这些东西的意义和区别:

 

    这里我简单说说:

    a Interlocked function: 原子操作函数,效率最高(估计是spin lock)

    Interlocked functions synchronize access to a variable that is shared by multiple threads.

    适合做一个整数变量的加法,减法,赋值等.

 

    b Critical Section:

       是用户级的实现(即不是操作系统创建管理的),所以只适用于一个进程内,效率比Mutex,Binary Semaphore要高。

      如不是跨进程通讯,尽量用这个。

    

    c   Mutex 和 Semaphore

     是系统级对象,所以性能差些(用户级和kernel级的上下文切换,比较费时)

     Mutex 类似于binary semaphore.

     Semaphore(信号量):出现的比较早,Unix就有,主要是进程(后来包括线程)通讯用的,当它的计数为1时,就退化成Mutex了,可以实现互斥操作。

    

      Mutex,Semaphore在windows的实现,效率相比如何,我也不知道,我只知道Mutex:同一时间,只让一个thread访问一个资源,而semaphore没有这个限制(用了等待多个条件是否满足)。

 

 

 

2  windows 有thread local storage机制, (要干什么,意思我忘了)

 

   首先,理解TLS,它实际上不是线程同步, 如g_count放在TLS中,每个thread有单独的一份g_count,互不干涉,独立变化。

 

  我想最好会写出TLS函数名(如带参数更好):

       TlsAlloc, TlsGetValue, TlsSetValue, TlsFree

 

   你看过windows multithread 编程的14章:413页附近,了解什么时候,使用TLS.

 

 

 

简答题2

 

 void parentThreadFunction(...)

 {

       createThread(childThreadFunction); 

 

}

 

void childThreadFunction

{

       GetThreadTimes(父线程)//

 

}

代码如何写,我不能完全写对。

 

解释一下意思: 这道题,就是一个线程创建了一个child thread,在child thread,用GetThreadTimes来获得父线程的运行时间信息。

问这样做有啥问题没有?

 

其实,我不太明白的。

 

答:

 1 要想GetThreadTimes获得线程的信息,那么这个线程在创建时, 提供了THREAD_QUERY_INFORMATION or THREAD_QUERY_LIMITED_INFORMATION访问权,做法是在createThread的安全参数那设置。

   此例子没有列出parentThread是如何创建的,所以,是不是考这个?

 

2  对一个已经退出的线程,使用GetThreadTimes当然也是可以的。

 

 

 

就这样回答吧:

 

  如这个parent thread有 THREAD_QUERY_INFORMATION or THREAD_QUERY_LIMITED_INFORMATION访问权, 这段代码就没有问题。

 

 

 

你可能感兴趣的:(C/C++,thread,semaphore,function,destructor,class,windows)