记一次面试中的相关问题

文章详细介绍了protobuf的序列化与反序列化机制,强调了其节省空间的特点。同时,解释了memcpy函数的作用和参数,特别是在处理内存重叠情况下的注意事项。此外,讨论了大端存储和小端存储的概念及其在网络编程中的应用。
摘要由CSDN通过智能技术生成

1. protobuf内部的实现原理

序列化与反序列化,比如对于数字它要求根据数字的大小选择存储空间,小于15的数字只用1个字节来表示,大于15的数用2个字节来表示,以此类推,这样要求可以尽可能地节省空间。Protobuf的一大特点是编码后的数据量很小,可以节省网络带宽。

还有一种说法是,JSON和MessagePack都使用字符串Key键值作为映射到程序变量的连接桥梁,用变量字符串去查看对应的Key键值是否存在,这样免不了因Key键值字符串太多而消耗更多空间。Protobuf则用数字编号来作为Key键值与变量映射的连接桥梁,每个变量都必须有一个不重复的标签号(即数字编号),使用Protobuf结构中变量字段后跟着的数字编号来映射数据中的数字编号,进而读取数据。Protobuf为每个结构变量都定义了一个标签号(即数字编号),这个数字编号就代表程序变量与指定编号数据的映射关系。

2. 实现函数 

void memcpy(void* dest, const void* source, size_t count);

参数说明:

void *dest:指向某一缓冲区,该缓冲区用来存放要拷贝的数据(即目标缓冲区)

const void *source:指向某一缓冲区,该缓冲区用来存放要拷贝给他人的数据(即源缓冲区)

size_t count:要拷贝多少个字节

功能说明:

此函数可将source缓冲区中前count个字节的数据拷贝到dest缓冲区中。请注意,当dest缓冲区和source缓冲区中有部分重叠的情形发生时,用户应使用memmove函数来进行数据的拷贝,因为这种情况下,memcpy并不能保证其结果是正确的。

返回值:

NULL。

实例代码:

#include <stdio.h>
#include <string.h>

#include <iostream>
#include <string>

using namespace std;

void memcpy(void* psrc, void* pdst, size_t length) {
  if (psrc == NULL || pdst == NULL) return;
  void* ret = psrc;
  if (pdst <= psrc || (char*)pdst >= (char*)psrc + length) {
    // 没有内存重叠,从低地址开始复制
    while (length--) {
      *(char*)pdst = *(char*)psrc;
      pdst = (char*)pdst + 1;
      psrc = (char*)psrc + 1;
    }
  } else {
    // 有内存重叠,从高地址开始复制
    psrc = (char*)psrc + length - 1;
    pdst = (char*)pdst + length - 1;
    while (length--) {
      *(char*)pdst = *(char*)psrc;
      pdst = (char*)pdst - 1;
      psrc = (char*)psrc - 1;
    }
  }
  return;
}

int main() {
  char* src[10] = {"C BIBLE"};
  char* dst[10] = {"C Bible"};

  cout << "Before memcpy..." << endl;
  cout << "src = " << *src << endl;
  cout << "dst = " << *dst << endl;

  memcpy(src, dst, 10);

  cout << "After memcpy..." << endl;
  cout << "src = " << *src << endl;
  cout << "dst = " << *dst << endl;

  return 0;
}

输出:

Before memcpy...
src = C BIBLE
dst = C Bible
After memcpy...
src = C BIBLE
dst = C BIBLE

关于内存重叠问题:

起初我不太明白,为什么两块分配好的内存空间,会有重叠的问题?后来了解到这种内存重叠在平时写的应用级代码中并不会出现,但是在内核和驱动代码中会存在内存重叠问题。

 图中灰色的部分即为内存重叠的部分,dst内存开始的地址在src所分配的内存中(这在应用层面的代码中是不可能出现的)。解决该问题的办法就是将代码从高地址向低地址进行复制。(复制完之后那原来的数据岂不就没办法使用了?这不是copy,将其改为move会更好些)

3. 大端存储和小端存储

大端存储:把字(4字节)的低位放在高地址位

小端存储:把字(4字节)的低位放在低地址位

采用大端模式进行存放有利于人类的思维模式,而采用小端模式更利于计算机处理。

互联网使用的网络字节序采用大端模式进行编址,而主机字节序根据处理器的不同而不同。socket编程时,可以使用系统提供的函数对大小端字节序进行转换。

网络编程的时候会使用itoa函数来将整数转换为字符串(IP:端口)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值