曲径通幽论坛

标题: 面试题目集锦[宏定义,预处理,const,sizeof] [打印本页]

作者: beyes    时间: 2011-11-16 14:56
标题: 面试题目集锦[宏定义,预处理,const,sizeof]
定义一个宏 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 类型,它是为了不同的系统之间的移植便利而创建。
作者: beyes    时间: 2011-11-16 15:46
标题: #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))

注意在宏中要小心的用括号将参数括起来。
作者: beyes    时间: 2011-11-16 16:19
标题: const
1. const 有什么用途,请至少说明两种

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

2. const 与 #define 相比有什么不同
在 C++ 中可以用 const 定义常量,也可以用 #define 定义常量,但是前者比后者有更多的有点:

作者: beyes    时间: 2011-11-17 14:26
标题: 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 的倍数来,所以就没必要进行扩展了。
作者: beyes    时间: 2011-11-17 15:17
标题: 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

作者: beyes    时间: 2011-11-18 10:42
标题: 题目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 个字节。




欢迎光临 曲径通幽论坛 (http://www.groad.net/bbs/) Powered by Discuz! X3.2