嵌入式面试学习笔记(入门1)

news2024/9/21 11:35:13

目录

指针的大小问题

sizeof和strlen

C语言分配内存的方式

数组(的)指针和指针(的)数组

union


指针的大小问题

指针对于不少新手而言是一道难关,但是不必恐惧于指针。他的本质其实就是一个地址。请冷静下来仔细思考。回顾一下对于当今已经普及的“64位计算机”这个说法。这个64不是空穴来风,他指代的是CPU内部的机器字长(一次运算可以处理的最大位数)的大小。那么,我们都知道计算机想要知道你想操作的数在哪,就很有必要提供一个“地址”告知操作数在何处。这就是“地址”。对于64位平台,地址显然是64位(MAR64位长度)。

那么指针实际上就是地址的一个“别称”了,当我们说一个指向某一个对象的指针,实际上就是再说这个对象的地址如何。

void handleTheDemo(int* ptr);
...
int  demo   = 3;
int* ptr    = &demo;
handleTheDemo(ptr)

回到这个问题,既然指针只是一个地址的存储器,那么,他显然跟类型完全无关!你想,对于你根据地址找人,这个人胖还是瘦,半毛钱关系没有,不会影响他的家庭住址地址丝毫。这样我们就可以猜到,对于如下的代码:

#include <stdio.h>
​
void displayPtrSize()
{
    printf("Size of pointer: %d\n", sizeof(void*));
    printf("Size of int pointer: %d\n", sizeof(int*));
    printf("Size of double pointer: %d\n", sizeof(double*));
    printf("Size of char pointer: %d\n", sizeof(char*));
    printf("Size of long pointer: %d\n", sizeof(long*));
    printf("Size of float pointer: %d\n", sizeof(float*));
    printf("Size of long long pointer: %d\n", sizeof(long long*));
    printf("Size of short pointer: %d\n", sizeof(short*));
    printf("Size of unsigned int pointer: %d\n", sizeof(unsigned int*));
    printf("Size of unsigned long pointer: %d\n", sizeof(unsigned long*));
    printf("Size of unsigned long long pointer: %d\n", sizeof(unsigned long long*));
    printf("Size of unsigned short pointer: %d\n", sizeof(unsigned short*));
    return;
}
​
int main()
{
    displayPtrSize();
    return 0;
}

其打印出来的结果是可想而知的。

那么,难道所有的平台上都是如此吗?显然不是,再仔细看看我的第一段话,我们只是在讨论64位平台,事实上还存在一个32位平台,如法炮制,不难猜出地址在这里就是32位了

# 64位平台运行结果
Size of pointer: 8
Size of int pointer: 8
Size of double pointer: 8
Size of char pointer: 8
Size of long pointer: 8
Size of float pointer: 8
Size of long long pointer: 8
Size of short pointer: 8
Size of unsigned int pointer: 8
Size of unsigned long pointer: 8
Size of unsigned long long pointer: 8
Size of unsigned short pointer: 8
# 32位平台运行结果
Size of pointer: 4
Size of int pointer: 4
Size of double pointer: 4
Size of char pointer: 4
Size of long pointer: 4
Size of float pointer: 4
Size of long long pointer: 4
Size of short pointer: 4
Size of unsigned int pointer: 4
Size of unsigned long pointer: 4
Size of unsigned long long pointer: 4
Size of unsigned short pointer: 4

sizeof和strlen

这个话题于我看来有些莫名其妙,后来笔者想到大部分学校喜欢在教授字符串的时候扣这些颇为无聊的小玩意,笔者决定分享一下我的看法。

我们认为sizeof这个东西是操作符,在C文件编译的时候就已经静态的计算好了,如果不信,可以看看这一份简单的C文件的汇编结果:

int main()
{
    int intSize = sizeof(int);
    return 0;
}
    .file   "demo.c"
    .text
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $48, %rsp
    .seh_stackalloc 48
    .seh_endprologue
    call    __main
    movl    $4, -4(%rbp)
    movl    $0, %eax
    addq    $48, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .def    __main; .scl    2;  .type   32; .endef
    .ident  "GCC: (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders, r3) 14.1.0"
​

可以看到我们的sizeof(int)直接被替换成为4了。这个玩意纯粹的是计算目标占用内存的大小。

那strlen呢?他又是怎么一回事呢,其实他是一个string.h里的库函数,用于求解字符串长度的

一个函数!一个操作符!首先差别就很大!

我们下一步是思考他们在字符串使用上的区别

#include <stdio.h>
#include <string.h>
​
int main() {
    char str[] = "buffer";
    printf("sizeof: %d\n strlen: %d\n", sizeof(str), strlen(str));
    return 0;
}

这段代码是显而易见的。不难猜出一个结果是

sizeof: 7 strlen: 6

为什么?我们知道,strlen在实现上不考虑'\0'的存在,他是我们字符串的公认终止符。

size_t strlen(const char* str){
    int size = 0;
    while(*str++) size++;
    return size;
}

可以查看各个编译器对string.h标准库的实现,这里笔者提供的是一个比较好理解的实现,可以发现当我们的*str == '\0'的时候,循环退出,size不自增。

而sizeof不在乎这些,他只知道我们的字符数组的大小是7个(6个字符,一个\0),因此事情就很简单。

Questions:如果我改变为

#include <stdio.h>
#include <string.h>
​
int main() {
    const char* str = "buffer";
    printf("sizeof: %d\n strlen: %d\n", sizeof(str), strlen(str));
    return 0;
}

请问此时又该如何呢?

仔细思考指针和数组是否严肃等价!

C语言分配内存的方式

其实就三种:

void display_bufferAllocation()
{
    static int _inDataSegment = 1; // 可以在任何地方定义,通通放到静态区
    int _inStackSegment = 2;
    int* __inHeapSegment = (int*)malloc(sizeof(int));
    ...
    free(__inHeapSegment);
}

1、静态存储区分配

内存分配在程序编译之前完成,且在程序的整个运行期间都存在,例如全局变量、静态变量等。

2、栈上分配

在函数执行时,函数内的局部变量的存储单元在栈上创建,函数执行结束时这些存储单元自动释放。

3、堆上分配

堆分配(又称动态内存分配)。程序在运行时用malloc或者new申请内存,程序员自己用free或者delete释放,动态内存的生存期由我们自己决定。

数组(的)指针和指针(的)数组

啥?好奇这个区别,嗨老铁,加一个(的)就搞定了。

int arr[10];
int* ptr_of_array = arr;
​
int* ptr_arr[10];
...

可以看到:数组的声明方式无非就是:

type var_name[size];

type是指针,那就是指针(的)数组。

union

这个有意思,我第一次看到的时候是在确定机器的大小端的时候出现的

#include <stdio.h>
union TestEndian
{
    unsigned int a;
    char b;
};
​
int check_endian()
{
    union TestEndian te;
    te.a = 0x12345678;
    if (te.b == 0x78)
        return 1;
    else
        return 0;
}
​
int main()
{
    printf("Endian: %d\n", check_endian());
    return 0;
}

为了理解这段代码,我们需要首先需要理解联合体是什么。

我们假想一种有意思的场景

我们需要对一系列的人进行信息存储,对于学生,我们需要存储的是学号;另一方面,对于教师只需要知道名字即可。

当然这个例子没有联合体在Linux进程信息应用上来的好,但是笔者还是决定考虑用这个蹩脚的例子来说明事情。除了抽象两个结果体之外,我们还可以这样做:

#include <stdio.h>
#include <stdlib.h>
typedef enum {
    STUDENT,
    TEACHER
}FellowType;
​
typedef struct 
{
    FellowType type;
    union {
        char studentName[20];
        unsigned int teacherID;
    } data;
}FellowInSchool;
​
FellowInSchool* createFellowStuent(FellowType type, char* name)
{
    FellowInSchool* fellow = (FellowInSchool*)malloc(sizeof(FellowInSchool));
    fellow->type = type;
    strcpy(fellow->data.studentName, name);
    return fellow;
}
​
FellowInSchool* createFellowTeacher(FellowType type, unsigned int id)
{
    FellowInSchool* fellow = (FellowInSchool*)malloc(sizeof(FellowInSchool));
    fellow->type = type;
    fellow->data.teacherID = id;
    return fellow;
}
​
void freeFellow(FellowInSchool* fellow)
{
    free(fellow);
}
​
void displayFellow(FellowInSchool* fellow)
{
    switch (fellow->type)
    {
    case STUDENT:
        printf("Student Name: %s\n", fellow->data.studentName);
        break;
    case TEACHER:
        printf("Teacher ID: %d\n", fellow->data.teacherID);
        break;
    default:
        printf("Invalid Fellow Type\n");
        break;
    }
}
​
int main()
{
    FellowInSchool* fellow1 = createFellowStuent(STUDENT, "John");
    FellowInSchool* fellow2 = createFellowTeacher(TEACHER, 1234);
    displayFellow(fellow1);
    displayFellow(fellow2);
    freeFellow(fellow1);
    freeFellow(fellow2);
    return 0;
}

你看,对于同一个FellowInSchool结构体可以产生复用,而大大节约内存,让一块内存根据条件的不同按照不同的姿势进行解读。就这个用处

仔细品鉴一下这句话,就会高兴的发现

union TestEndian
{
    unsigned int a;
    char b;
};

其实很简单:

你看,这就是小端法的存0x12345678的方式,可以看到,如果我们采取char 的方式读取读到的就是0x78,大端法这里填写的就是0x12,这样我们就实际上测试了这个机器是不是小端法的机器了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2152213.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于yolov8和openpose人体骨骼关键点实现的摔倒姿态识别检测系统实现

【参考源码】 GitHub - HRonaldo/Openpose_YOLO 本项目参考上面框架进行全面改进&#xff0c;改进如下&#xff1a; &#xff08;1&#xff09;将检测框架换成当前最流行框架yolov8&#xff0c;并封装成类实现模块化设计。关于yolov5优化项目可以访问&#xff1a;https://bl…

【华为杯研赛赛题】2024年中国研究生数学建模竞赛赛题已出

2024年中国研究生数学建模竞赛所有赛题已出&#xff01; A题 B题 C题 D题 E题 F题

【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL77

编写乘法器求解算法表达式 描述 编写一个4bit乘法器模块&#xff0c;并例化该乘法器求解c12*a5*b&#xff0c;其中输入信号a,b为4bit无符号数&#xff0c;c为输出。注意请不要直接使用*符号实现乘法功能。 模块的信号接口图如下&#xff1a; 要求使用Verilog HDL语言实现以上…

使用 Elasticsearch Reindex API 迁移数据

使用 Elasticsearch Reindex API 迁移数据 在 Elasticsearch 中&#xff0c;随着需求的变化&#xff0c;可能需要对索引进行重建或更新。这通常涉及创建新索引、迁移数据等步骤。本文介绍如何使用 Reindex API 将旧索引中的数据迁移到新索引中 一、步骤概述 创建新索引&#…

OpenCV_距离变换的图像分割和Watershed算法详解

在学习watershed算法的时候&#xff0c;书写代码总会出现一些错误&#xff1a; 上述代码运行报错&#xff0c;显示OpenCV(4.10.0) Error: Assertion failed (src.type() CV_8UC3 && dst.type() CV_32SC1) in cv::watershed 查找资料&#xff1a;目前已解决 这个错…

idea 编辑器常用插件集合

SequenceDiagram 用于生成时序图的插件&#xff0c;支持一键生成功能。 使用&#xff1a;选择某个具体的方法&#xff0c;点击右键菜单&#xff0c;选择“Sequence Diagram” 便可生成相应的时序图 例子&#xff1a; 效果&#xff1a; Code Iris Code Iris可以根据代码自动…

c++day3 手动封装一个顺序表(SeqList),分文件编译实现

要求: 有私有成员&#xff1a;顺序表数组的起始地址 ptr、 顺序表的总长度&#xff1a;size、顺序表的实际长度&#xff1a;len 成员函数&#xff1a;初始化 init(int n) 判空&#xff1a;empty 判满&#xff1a;full 尾插&#xff1a;push_back 插入&#xff1a;insert&…

优数:助力更高效的边缘计算

在数字化时代的浪潮中&#xff0c;数据已成为企业最宝贵的资产之一。随着物联网&#xff08;IoT&#xff09;设备的激增和5G技术的兴起&#xff0c;我们正迅速步入一个新时代&#xff0c;在这个时代中&#xff0c;数据不仅在量上爆炸性增长&#xff0c;更在速度和实时性上提出了…

Hadoop里面MapReduce的序列化与Java序列化比较

什么是序列化&#xff1f; jvm中的一个对象&#xff0c;不是类&#xff0c;假如你想把一个对象&#xff0c;保存到磁盘上&#xff0c;必须序列化&#xff0c;你把文件中的对象进行恢复&#xff0c;是不是的反序列化。 假如你想把对象发送给另一个服务器&#xff0c;需要通过网…

线性dp 总结详解

就是感觉之前 dp 的 blog 太乱了整理一下。 LIS(最长上升子序列) 例题 给定一个整数序列&#xff0c;找到它的所有严格递增子序列中最长的序列&#xff0c;输出其长度。 思路 拿到题目&#xff0c;大家第一时间想到的应该是的暴力(dp)做法&#xff1a; #include <bits/s…

基于Windows系统以tomcat为案例,讲解如何新增自启动服务,定时重启服务。

文章目录 引言I 设置服务自启动的常规操作II 安装多个tomcat服务,并设置自启动。III 定时重启服务引言 为了同一个版本安装多个tomcat服务,并设置自启动。使用Windows的任务计划程序来创建一个定时任务,用于重启Tomcat服务。I 设置服务自启动的常规操作 运行窗口输入control…

2024双11有哪些值得入手的好物?2024年双十一好物推荐

随着2024年双十一购物狂欢节的临近&#xff0c;消费者们正摩拳擦掌&#xff0c;准备迎接这场年度最大的网购盛会。面对琳琅满目的促销信息和令人眼花缭乱的商品&#xff0c;如何在海量商品中精准锁定那些真正值得购买的好物&#xff0c;成为每位精明买家的首要任务。本文旨在为…

牛啊,GitHub 代理加速图文教程

大家好&#xff0c;众所周知&#xff0c;GitHub 在国内访问速度堪忧&#xff0c;经常出现访问不了的情况&#xff0c;如果我们去 clone 代码&#xff0c;网速非常差。今天教大家如何给 GitHub 进行加速。 要用到我开发的开源项目 Cloudflare Workers Proxy&#xff0c;它是一个…

视频压缩篇:适用于 Windows 的 10 款最佳视频压缩器

视频压缩器现在对许多想要减小视频大小的视频编辑者来说非常有名。但是&#xff0c;并非所有可以在网上找到的视频压缩器都能产生最佳输出。因此&#xff0c;我们搜索了可以无损压缩视频的最出色的视频压缩器应用程序。本文列出了您可以在离线、在线和手机上使用的十大最佳视频…

2024华为杯研赛D题保姆级教程思路分析+教程

2024年中国研究生数学建模竞赛D题保姆级教程思路分析 D题&#xff1a;大数据驱动的地理综合问题&#xff08;数学分析&#xff0c;统计学&#xff09; 关键词&#xff1a;地理、气候、统计&#xff08;细致到此题&#xff1a;统计指标、统计模型、统计结果解释&#xff09; …

无线领夹麦克风哪个降噪好?一文搞懂麦克风什么牌子的音质效果好

对于视频拍摄、直播来说&#xff0c;一款好的拾音麦克风是不可或缺的。作为一位数码博主&#xff0c;也是会经常拍摄视频讲解&#xff0c;早期没有使用麦克风时&#xff0c;声音不够清晰&#xff0c;而且周围环境音也会同时被收录&#xff0c;导致整个音频的音质效果极差&#…

【多线程】CAS的原理及应用,看这篇文章就够啦

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;多线程 / javaEE初阶 一、CAS概述 CAS&#xff08;Compare and Swap&#xff09;&#xff0c;中文译为 “比较并交换” &#xff0c;是一种无锁算法中常用的原子操作。CAS通常用于实现线程之间的同…

力扣之1459.矩形面积

1. 1459.矩形面积 1.1 题干 表: Points ---------------------- | Column Name | Type | ---------------------- | id | int | | x_value | int | | y_value | int | ---------------------- id 是该表中具有唯一值的列。 每个点都用二维坐标 (x_value, y_value) 表示。 编…

【力扣每日一题——2374. 边积分最高的节点】python

2374. 边积分最高的节点 给你一个有向图&#xff0c;图中有 n 个节点&#xff0c;节点编号从 0 到 n - 1 &#xff0c;其中每个节点都 恰有一条 出边。 图由一个下标从 0 开始、长度为 n 的整数数组 edges 表示&#xff0c;其中 edges[i] 表示存在一条从节点 i 到节点 edges[…

大模型训练实战经验总结

在当今AI技术飞速发展的背景下&#xff0c;定制化大模型的自主训练已成为满足特定行业需求、保障数据安全、提升模型应用效能的关键途径。本文将深度剖析这一过程的核心价值与实践智慧&#xff0c;从数据隐私保护、模型透明度增强&#xff0c;到数据预处理的精细操作&#xff0…