嵌入式笔试刷题专栏(第一天)

1.(void *)ptr和(*(void **))ptr的结果是否相同? 其中ptr为同一个指针

第 1 题:void *ptr*(void **)ptr 有什么区别?

📌 考点: 指针类型转换、void 指针用法

👀 易错点: 误以为 void* 可直接解引用

  • void *ptr; 是一个通用指针,指向任意类型,但不能直接解引用(没有类型信息)。
  • *(void **)ptr:假设 ptr 本身是一个 void** 类型的变量,即 ptr 指向一个 void*,可以解引用得到一个 void*

🧠 举例:

void *a = malloc(4);
void **b = &a;
void *c = *b;  // 相当于 *(void **)b,没问题

void *x = b;   // 错误用法!x 是 void*,不能表示 void**
void *y = *x;  // 错误,void* 不能解引用

2.要对绝对地址0x100000赋值,我们可以用(unsigned int *)0x100000=1234; 那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?

第 2 题:如何跳转到 0x100000 执行一段程序?

📌 考点: 裸机开发、函数指针强制转换

🧠 在嵌入式中,经常需要跳转到特定 Flash/ROM 地址执行,比如 OTA 升级、Bootloader 跳转。

🧾 写法如下:

typedef void (*jump_func)(void);
jump_func jump = (jump_func)0x100000;
jump();  // 跳转到 0x100000 处执行

⚠️ 注意:

  • 必须确认该地址有有效代码,并且是可执行段。
  • 跳转前可能要关闭中断、重配置堆栈等。

3.给定结构体

   struct A

   {

       char t:4;

       char k:4;

       unsigned short i:8;

       unsigned long m;

}; 问sizeof(struct A)是多少?

第 3 题:结构体位域的 sizeof

📌 考点: 内存对齐、位域填充

结构体位域字段虽然按位分配,但实际大小依赖对齐规则。

🧠 示例:

struct A {
    unsigned int a:1;
    unsigned int b:3;
    unsigned int c:2;
};
std::cout << sizeof(A) << std::endl; // 输出 4 或 8,依实现而异

  • 一般位域按 int 对齐。
  • 关键点:不能假设位域节省空间,需依赖编译器布局策略。

4..int main()

 {

 

}

第 4 题:空的 main() 函数会返回什么?

📌 考点: main 函数返回值

int main() { }

⛔ 这其实是 UB(未定义行为),虽然一些编译器会默认补上 return 0;,但标准要求返回值必须明确。

✔ 推荐:

int main() {
    return 0;
}

5.编写函数void hton(float val,char *buf)把小端序的val转换成大端序的val,存放到buf中

第 5 题:实现 hton(float)

📌 考点: 浮点数与字节序转换

htonl 只能处理整数类型,如何将 float 进行大端转换?

🧾 示例实现:

float htonf(float val) {
    uint32_t temp;
    memcpy(&temp, &val, sizeof(temp)); // float → uint32
    temp = htonl(temp);                // 使用现成的字节序函数
    memcpy(&val, &temp, sizeof(val));  // 还原 float
    return val;
}

6.写出int,bool,float,指针变量与“零值”比较的if语句

第 6 题:int、bool、float、void 与 0 的比较

📌 考点: 类型与布尔判断

各类型与 0 比较会有不同隐含语义:

  • int a = 0;false
  • bool b = false;false
  • float f = 0.0;false
  • void* p = nullptr;false

if (x) 中,全部都可被转换为布尔判断,0 都是假

7.请指出如下语句的含义

          void *(*(p1)(int))[10];

          float (*(*p2)(int,int,float))(int);

          typedef double (*(*(*p3)())[10])();

          int (*(*p4())[10])();

第 7 题:数组指针 & 函数声明分析

📌 考点: 指针声明逆向分析法

int (*p1)[10];      // p1 是指向含10个int的数组的指针
int *p2[10];        // p2 是含10个int指针的数组
int (*fp1)(int);    // fp1 是指向函数的指针,函数参数为int
int *(*fp2)(int*);  // fp2 是指向函数的指针,该函数参数为int*,返回int*

🧠 技巧: 从标识符往外读,遇到 () 先读函数,再读指针或数组。

8.现有1M长度的char数组,请将每个字节进行高低位互换(一个字节的八位二进制逆序),如果我们需要频繁地处理这样的数据,请实现一个高效的处理函数

第 8 题:高效字节反转(bit reverse)

📌 考点: 位运算技巧

目标:将一个字节的位顺序反转。例如:

输入:0b11010010
输出:0b01001011

🧾 解法:查表法 或 分步交换法

uint8_t reverse(uint8_t b) {
    b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
    b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
    b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
    return b;
}

9.用DrawPixel(x,y)画点函数实现一个void DrawLine(int x1,int y1,int x2,int y2)划线函数

第 9 题:DrawLine(x1, y1, x2, y2)

📌 考点: Bresenham 直线算法

用最基本的点绘制函数画线,要求无浮点数运算。

🧾 简化实现(整数版)

void DrawLine(int x1, int y1, int x2, int y2) {
    int dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1;
    int dy = -abs(y2 - y1), sy = y1 < y2 ? 1 : -1;
    int err = dx + dy, e2;

    while (true) {
        DrawPixel(x1, y1);
        if (x1 == x2 && y1 == y2) break;
        e2 = 2 * err;
        if (e2 >= dy) { err += dy; x1 += sx; }
        if (e2 <= dx) { err += dx; y1 += sy; }
    }
}

10.如下程序有什么问题,请指出

    void test()

    {

       char string[10];

       char *str1=0123456789;

       strcpy(string,str1);

}

第 10 题:字符串拷贝导致溢出

📌 考点: 缓冲区溢出、strlen vs strcpy

典型错误:

char a[5];
strcpy(a, "hello");  // 溢出,因为 "hello" 长度为 6(含 '\0')

✔ 安全版本:

strncpy(a, "hell", 4);  // 或者 malloc 动态分配空间

嵌入式笔试专栏 文章被收录于专栏

本专栏系统整理了嵌入式方向笔试中常见的知识点和高频考题,涵盖基础理论、常用算法、C语言陷阱、操作系统原理、驱动开发、常见外设通信协议(如 I2C/SPI/UART)、RTOS、Linux 内核、以及实用电路知识等内容。

全部评论

相关推荐

评论
点赞
2
分享

创作者周榜

更多
牛客网
牛客企业服务