曲径通幽论坛
标题: 面试题目集锦[宏定义,预处理,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 定义常量,但是前者比后者有更多的有点:
const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,并且在字符替换中可能会产生意料不到的错误(边际效应)。
有些集成化的调试工具可以对 const 常量进行调试,但不能对宏常量进行调试。在 C++ 程序中只使用 const 常量而不使用宏常量,即 const 常量完全替代宏常量。
作者: 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 上的输出为:在 GCC 上的输出为:
作者: 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 |