Win/Linux下操作ini配置文件(API)

 我们的程序常常需要从配置文件中获取参数,一方面,用户关于程序的自定义配置往往就存储在配置文件中,自定义配置的适配与保存就转化为对配置文件的读写操作;另一方面,也是本文编写的由来,那就是将有关程序中核心算法的参数提取到配置文件,方便算法参数的调试(只要调整配置文件,无需修改程序源码,更无需重新构建)。
 .ini 文件作为典型的配置文件,其文件存储的内容基本上是一些参数的 Key-Value 形式,此外就是一些所谓的属性段,多个对同一方面参数进行描述的 键值对 可以归纳为一个 Section
 下面,是 Win/Linux 下如何通过不同的 API 实现对 *.ini 配置文件读写操作的整理。

使用 select 函数实现更为精确的延时

select 初识

1
2
3
4
5
6
7
8
9
10
11
12
int select(
_In_ int nfds, // 忽略,仅是为了与Berkeley套接字兼容
_Inout_ fd_set *readfds, // 指向一个套接字集合,用来检查其可读性
_Inout_ fd_set *writefds, // 指向一个套接字集合,用来检查其可写性
_Inout_ fd_set *exceptfds, // 指向一个套接字集合,用来检查错误
_In_ const struct timeval *timeout // 指定此函数等待的最长时间,如果为NULL,则最长时间为无限大
);

返回值:
函数调用成功,返回发生网络事件的所有套接字数量的总和
如果超时返回0,代表在描述词状态改变前已超过timeout时间;
当有错误发生时则返回SOCKET_ERROR(-1).

瞎谈 Socket 编程(二)

数据传输方式

  SOCK_STREAM    面向连接        准确性/相对较慢   TCP
  SOCK_DGRAM     无连接的传输方式     视频/音频       UDP
Server
 1. 创建套接字                 int sock = socket(AF_INET, SOCK_STREAM, 0);
 2. 将套接字和IP、端口绑定           bind(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
 3. 进入监听状态,等待客户端请求        listen(…);
                        accept(…);
 4. 接受客户端数据/向客户端发送数据       read(…)/write(…);              
 5. 关闭套接字                 close();

Client
 1. 创建套接字
 2. 向服务器(特定的IP和端口)发送请求       connect(…);
 3. 读取服务器传回的数据/向服务器发送数据    read/write(sock, char*, sizeof(…));
 4. 关闭套接字

瞎谈 Socket 编程(一)

  从项目中一个实例说起,我们的目标是将决策层做出的控制小车的决策(主要是速度velocity还有角速度angular),通过TCP网络传输的方式传递到与控制小车的FPGA相连接的RaspberryPi。也许你会问,为毛要通过网络传输,不能通过其他方式,比如串口,不是会更快点吧?
  Maybe…不过,这是有原因的。
  其一,我觉得应该通过以太网线直接将运行决策的PC机网卡与树莓派上的网卡直接相连接,再用网络传输,应该比串口快,或者说,更稳定高效。遗憾的是,我们没办法通过以太网线直接相连,而是通过WiFi,这是因为,其二,PC机唯有的一个以太网卡,拿去插激光雷达了,而激光雷达作为一个sensor,是决策所必须的。
  其三,整个体系运行在ROS之上,而,把ROS体系中做出来的决策送到控制端的树莓派上,我们得自己想办法或者说Coding。刚好,找到有一个开源的ros通讯,恰好人家是通过TCP传输的,所以,就没想那么多,直接用上了。
  可想而知,这个开源的ros通讯要做的,就是把决策层做出来的velocity和angular,通过tcp传送到运行在树莓派上的程序进而控制FPGA控制小车。搞过ROS的应该知道,在ROS中节点都是通过消息进行通讯的,那么,这个ros通讯节点要做的肯定就是订阅决策层做出来的关于控制的消息,然后通过网络传输出去,这些,你可以阅读 这个开源项目 的源码进行了解。

C语言中结构体内存free

  来自实训第三天的某段代码,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct vec2f {
float x;
float y;
};
typedef struct vec2f vec2f;

vec2f* vec2f_alloc() {
vec2f* ret;
ret = ( vec2f* ) malloc( sizeof( vec2f ) );
//if( !ret ) // if error occurs
return ret;
}

void vec2f_init( vec2f* v, float x, float y ) {
v->x = x;
v->y = y;
}

vec2f* vec2f_new( float x, float y ) {
vec2f* ret = vec2f_alloc();
vec2f_init( ret, x, y );
return ret;
}

void vec2f_delete( vec2f** v ) {
free( *v );
*v = NULL;
}

void vec2f_print( const vec2f* v ) {
printf( "[ %g %g ]\n", v->x, v->y );
}

Java到底是不是一种纯面向对象语言?

  参考博文 《Java到底是不是一种纯面向对象语言?》

  JVM 在创建对象的时候,实际上会创建两个对象:
   一个是实例对象。
   另一个是 Class 对象。该 Class 对象在 JVM 内仅仅会装载一次,该类的静态方法和静态属性也一同装载,JVM 使用该 Class 对象来创建具体的实例对象。
  例如,在下面的 Java 语句中,将有两个对象被创建:
    Employee emp = new Employee();
  一个是实例对象 emp ;另一个则是 Class 对象,我们可以通过 Employee.class 引用到它;这个 Class 对象拥有所有的这个类定义的静态变量和静态方法,同时,如果我们访问 通过 emp 对象来访问静态内容,会发现它其实指向的对象就是 Employee.class

  静态内容确实被证实属于一个对象
   为什么静态内容在一个对象中(不管是emp还是emp2)改变了,在另一个对象中也同时改变,因为这两个对象改变的都是在 Employee.class 同一个对象里面的内容。

  Java 官方为每一个原始类型推出了对应的包装类(比如:Integer 对应 int,Long 对应 long,Character 对应 char),所以,其实现在我们可以为原始类型创建一个包装对象,同时对它们做对象相关的操作。
   JVM看来它把所有的 “原始类型” 都是当作对象处理”