曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 5855|回复: 5
打印 上一主题 下一主题

面试题目集锦[宏定义,预处理,const,sizeof]

[复制链接]

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
跳转到指定楼层
楼主
发表于 2011-11-16 14:56:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
定义一个宏 FIND 求一个结构体 struc 里某个变量相对 struc 的偏移量。


[C++] 纯文本查看 复制代码
#define FIND(struc, e) (size_t) &(((struc *)0->e)


说明
(struc *)0 表示将常量 0 强制转化为 struc * 型指针,我们可以认为,所声明的 struc 类型结构变量的起始地址就在 0 处(当然实际上不可能,这是个带有封闭性且相对的说法)。这样一来, &(((struc *)0->e) 就表示成员 e 的地址,且正因为该结构体的首地址为 0,所以实际就是说的了成员 e 到首地址的偏移量。

size_t 是一种数据类型,它一般被定义为 unsigned int 类型,它是为了不同的系统之间的移植便利而创建。

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
沙发
 楼主| 发表于 2011-11-16 15:46:52 | 只看该作者

#define 与 宏

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

宏定义:
[C++] 纯文本查看 复制代码
#define SECONS_PER_YEAR (60 * 60 * 24 * 365)UL

该题考察 #define 语法的基本知识,如不能以分号结束,括号的使用等。意识到该表达式可能会造成一个 16 位机的整型数溢出,所以使用了 UL 告诉编译器使用了无符号长整型。

题目二
写一个 “标准” 宏 MIN,这个宏输入两个参数并返回较小的一个。

宏定义:
[C++] 纯文本查看 复制代码
#define MIN(A,B)  ((A) <= (B) ? (A) : (B))

注意在宏中要小心的用括号将参数括起来。

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
板凳
 楼主| 发表于 2011-11-16 16:19:56 | 只看该作者

const

1. const 有什么用途,请至少说明两种

在 C 程序中,const 的用法主要有定义常量,修饰函数参数,修饰函数返回值。在 C++ 中,它还可以修饰函数的定义体,定义类中某个成员为恒态函数,即不改变类中的数据成员。被 const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

2. const 与 #define 相比有什么不同
在 C++ 中可以用 const 定义常量,也可以用 #define 定义常量,但是前者比后者有更多的有点:
      const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,并且在字符替换中可能会产生意料不到的错误(边际效应)。
      有些集成化的调试工具可以对 const 常量进行调试,但不能对宏常量进行调试。在 C++ 程序中只使用 const 常量而不使用宏常量,即 const 常量完全替代宏常量。

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
地板
 楼主| 发表于 2011-11-17 14:26:03 | 只看该作者

gcc 与 vc2010 中 sizeof 结构体时的不同

gcc 和 vc2010 对求结构体的 sizeof 会有所不同。比如下面这段程序:
[C++] 纯文本查看 复制代码
#include <stdio.h>

struct temp {
        short a1;
        short a2;
        short a3;
}A;

struct temp1 {
        short a1;
        long  a2;
}B;

struct temp2 {
        char a1;
        short a2;
}C;

struct temp3 {
        char a1;
        double a2;
}D;

int main()
{
        printf ("%d %d %d %d\\n", sizeof(A), sizeof(B), sizeof(C), sizeof(D));

        printf ("Address A: %p\\n", &A);
        printf ("Address B: %p\\n", &B);
        printf ("Address C: %p\\n", &C);
        printf ("Address D: %p\\n", &D);

        return 0;
}


使用 gcc 编译后运行输出:
./sizeof
6 8 4 12
Address A: 0x804a028
Address B: 0x804a030
Address C: 0x804a038
Address D: 0x804a01c
使用 vc2010 编译后运行输出:
6 8 4 16
Address A: 00F17154
Address B: 00F1714C
Address C: 00F17148
Address D: 00F17138
由两者的输出可见,VC2010 计算 struct temp3 这个结构体的大小为 16 个字节,也就是说它将第一个 a1 的变量的空间扩展为和 double 一样的 8 个字节了。

而在 gcc 的编译中,a1 只扩展了 4 个字节。

CPU 的优化规则大致这样:对于 n 字节的元素 (n = 2, 4, 8,...),它的首地址要能被 n 整除,才能获得最好的性能。设计编译器时可以遵循这个原则:对于每一个变量,可以从当前位置向后找到第一个满足这个条件的地址作为首地址。为了验证这个说法,我们将上面的代码里的结构体稍作修改:
[C++] 纯文本查看 复制代码
#include <stdio.h>


struct temp {
        short a1;
        short a2;
        short a3;
}A;

struct temp1 {

        char a1;
}B;

struct temp2 {
        char a1;
        short a2;
}C;

struct temp3 {
        char a1;
        double a2;
}D;

int main()
{
        printf ("%d %d %d %d\\n", sizeof(A), sizeof(B), sizeof(C), sizeof(D));

        printf ("Address A: %p\\n", &A);
        printf ("Address B: %p\\n", &B);
        printf ("Address C: %p\\n", &C);
        printf ("Address D: %p\\n", &D);

        return 0;
}

GCC 编译运行输出:
6 1 4 12
Address A: 0x804a028
Address B: 0x804a02e
Address C: 0x804a030
Address D: 0x804a01c
VC2010 编译运行输出:
6 1 4 16
Address A: 00397138
Address B: 0039713E
Address C: 00397150
Address D: 00397140
对比两种编译器编译后的运行输出,B 结构体只有一个 char 变量,只占用 1 个字节,而两个编译器都将其扩展到 2 个字节后才安排 C 结构的首地址。
另一方面,结构体A  到 结构体B 之间的距离就 6 个字节,并没有扩展为 8 个字节后再安排 B 结构体的首地址,因为寻址 A 结构体中的元素时地址是按照 2 的倍数来,寻址 B 结构体中的元素是地址也是按照 2 的倍数来,所以就没必要进行扩展了。

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
5#
 楼主| 发表于 2011-11-17 15:17:14 | 只看该作者

sizeof

求解下面程序的结果:
[C++] 纯文本查看 复制代码
#include <iostream>
using namespace std;

class A1
{
public:
        int a;
        static int b;

        A1();
        ~A1();
};

class A2
{
public:
        int a;
        char c;

        A2();
        ~A2();
};

class A3
{
public:
        float a;
        char c;
        A3();
        ~A3();
};

class A4
{
public:
        float a;
        int b;
        char c;
        A4();
        ~A4();
};

class A5
{
public:
        double d;
        float a;
        int b;
        char c;
        A5();
        ~A5();
};

int main() 
{
        cout << sizeof(A1) << endl;
        cout << sizeof(A2) << endl;
        cout << sizeof(A3) << endl;
        cout << sizeof(A4) << endl;
        cout << sizeof(A5) << endl;

        return 0;
}

上面程序对于最后求 sizeof(A5) 在不同的编译器上会有不同的结果,在 VC 上一般是 24 ,在 GCC 里则为 20 。VC 对最后的 char c 补齐 7 个字节,使整个结构体是按照 8 个字节对齐的:double d 为 8 个字节,float a 和 int b 各为 4 个字节合起来就是 8 个字节,char c 扩展补齐后为 8 个字节。
GCC 则以 4 个字节对齐,认为 double d 的 8 个字节由两个 4 字节组成,float a 和 int b 分别为 4 个字节,最后的 char c 补齐扩展为 4 个字节。

因此在 VC2010 上的输出为:
4
8
8
12
24
在 GCC 上的输出为:
4
8
8
12
20

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
6#
 楼主| 发表于 2011-11-18 10:42:35 | 只看该作者

题目6

1. 定义 int **a[3][4] 占用多少字节?
这是个二维数组,数组的元素是整形指针的指针,不管是什么指针,在 32 位机里总是 4 个字节的,所以该数组占用的内存大小为 3x4x4 = 48 个。

2. 以下代码的输出结果是多少?
[C++] 纯文本查看 复制代码
char var[10];
int test (char var[])
{
  return sizeof(var);
}

结果为 4 。因为 var[] 等价于 *var,当数组名以形参传递给函数时,已经退化为一个指针。

3. 以下代码的输出结果是多少?
[C++] 纯文本查看 复制代码
#include <iostream>
using namespace std;


class B
{
        float f;
        char p;
        int adf[3];
};


int main()
{
        cout << sizeof(B) << endl;


        return 0;
}

float 占 4 个字节,char 占 1 个字节,整型数组 adf 占 12 个字节,总共为 17 个字节。但是根据内存对齐原则,char p 这个变量要被扩展为 4 个字节,所以该类的大小为 20 个字节。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-4-29 01:06 , Processed in 0.070764 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表