404频道

学习笔记

上次文章《Windows和Linux之间的中文编码问题》中提到的在Windows下的源代码程序放到Linux下出现中文编码问题,解决方法为通过iconv工具转换源代码文件的编码为UTF8格式。最近多学习了些字符编码的知识,发现了解决此问题的另外一种办法。

基础知识

我们在编译程序的时候会涉及到几个编码问题,包括C++源文件的编码、C++程序的内码和运行环境编码,其中C++程序的内码较难理解。

C++程序的内码是指在可执行文件中字符串常量是以什么编码形式存放的,其中字符串常量为窄字符形式。在Windows系统中C++的内码通常为GB18030,在Linux下的gcc/g++使用的内码默认为utf8,可以通过fexec-charset参数来修改。

运行环境编码即为操作系统的编码,通常情况下,简体中文Windows操作系统编码为GB18030,而Linux下默认为UTF8。

gcc命令的参数

gcc有两个参数可以用来解决编码问题。
-finput-charset:用来指定源文件的编码。
-fexec-charset:用来指定生成的可执行文件的编码。

如果这两个参数均未指定,则GCC不会对编码进行转换。
以上这两个参数就可以用来在不修改源文件编码的基础上来达到正确的效果,达到和上篇文章中解决问题同样的效果。

关于Unicode编码

一直对Unicode编码比较糊涂,Unicode只是编码方法规范,而不是具体的存储方法。
常用的Unicode又分为UCS-2和UCS-两种编码,其中UCS-2采用固定的2个字节存储,UCS-4采用固定的4个字节存储。
通常情况下提到的Unicode编码即为UCS-2编码,比如Windows记事本中的保存为Unicode编码,其实就是保存为了UCS-2编码,由于每个字符均为2个字节,所以下次读取的时候仍然可以通过存储格式还原出来。

参考文章

字符编码笔记:ASCII,Unicode和UTF-8
字符编码详解
关于c++的一些编码问题

最近设置一个Linux下的截屏程序的开机自启动,Linux的XWindow系统为gnome。

最先想到的方式是修改/etc/inittab文件,因为Linux在开机自启动的时候会执行该文件,该文件的读取时机是在界面启动之前。我写了一个在main函数中睡眠10分钟的小程序,然后将程序添加到/etc/inittab文件中,结果开不了机了,因为需要睡眠10分钟后才能往下执行程序。幸好我用的虚拟机做的测试,并且在做测试之前备份了虚拟机。

仔细想一下在/etc/rc.d/rc.local文件中启动截屏程序肯定是不合适的,因为如果用户默认是以运行级别非5启动,则程序仍然会被调用,但是没有XWindow,谈何截屏。

接下来考虑将程序放到/etc/rc5.d目录下,这样就可以保证程序在XWindow环境下运行了。仔细一想也不合适,rc5.d仅在系统启动时运行,而Linux系统是多用户系统,允许多个用户同时登陆,多个用户登陆时截屏程序会怎样处理呢?这样显然不合适。

然后想到程序既然为截屏程序,多个用户登陆的时候应该有几个用户就跑几个程序,这样才能保证每个用户的屏幕都能截取到。因此应该放到用户登录后的启动程序列表中。类似于windows系统中的开机启动项。我用的桌面为gnome,找到了gnome-session-properties命令来启动添加程序启动的界面,然后将我的程序添加到界面中即可。

如果桌面系统为KDE,则应该也可以找到相关的设置界面。

题外:利用/etc/inittab和rc5.d目录下添加脚本的方式来启动程序的用户为root,很多程序未了避免root权限带来的安全问题,程序内部采用了su - 用户名的方式切换到一半用户执行代码。程序还可以通过chroot的方式更改根目录的路径达到保护系统的目的。

在开发Linux程序的时候通常会在Windows下编码,然后拿到Linux下编译调试。而两个操作系统之间的默认编码往往有差别。

文件编码问题

在Windows下查看文件编码可以使用记事本打开文件,然后点击“另存为”在右下角即可看到当前文件的编码方式。如果显示为ANSI编码,在简体中文系统下,ANSI 编码代表 GB2312 编码。不同 ANSI 编码之间互不兼容,ANSI是American National Standards Institute的缩写, 记事本默认是以ANSI编码保存文本文档的。

在Linux可以通过vi命令查看文件编码,用vi打开文件,然后输入:set encoding即可显示文件编码。

在VS2008中创建文件的默认编码是根据当前系统的编码格式确定的。VS2008编译器可以同时支持GB2312和UTF-8两种编码。

为了解决在Linux下的乱码问题,Linux下的编码格式为utf8编码,这里采用在Windows下将gb2312编码更改为utf8的方式来解决。iconv是一个可以转换文件编码的工具,编写一个批处理脚本来实现批量转换文件编码的功能。批处理文件的内容如下:

1
2
3
4
5
6
7
@ECHO OFF
FOR /R %%F IN (*.h,*.cpp) DO (
echo %%~nxF
iconv.exe -f GB2312 -t UTF-8 %%F > %%F.utf8
move %%F.utf8 %%F >nul
)
PAUSE

本脚本来自网络,不是我自己写的。
注意:在使用文件编码之前一定要备份文件,防止意外发生,否则后果自负。

文件名编码问题

Windows的中文系统下文件名的编码默认为gbk,在Linux默认编码为UTF-8。如果将Windows下的中文文件名的文件复制到Linux下肯定会出现乱码的问题。可以利用convmv工具来解决编码的问题。

具体执行操作为:在Linux系统下的要转换编码的目录下执行命令:convmv -f GBk -t UTF-8 --notest -r *,这样就会将该文件夹下的所有文件递归的转换编码为UTF-8。

convmv的帮助文档点这里

相关下载

脚本和iconv程序下载链接

无继承情况下的对象构造

在《Unix环境高级编程》的7.6节中提到C程序的内存空间可以分为正文段、初始化数据段、非初始化数据段、栈、堆。其中初始化数据段包含程序中需明确赋初值的变量,如C语言中的全局变量int maxcount = 99;。非初始化数据段又称为bss(block started by symbol)段,在程序开始之前,内核将此段初始化为0或空指针,如出现在函数外面的long sum[1000];,该变量没有明确赋初值,因此放到了bss段中。
而在C++语言中,将所有的全局对象当做初始化过的数据来对待,因此不会将全局变量放到bss段中。

POD数据类型

书中提到Plain ol’ data,查了下应该叫Plain Old Data,简称POD,指C风格的struct结构体定义的数据结构,其中struct结构体中只能定义常规数据类型,不可以含有自定义数据类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef struct Point
{
float x, y, z;
} Point;

Point global;

Point foobar()
{
Point local;
Point *heap = new Point();
*heap = local;
delete heap;
return local;
}

首先看全局变量global,按照常规的理解,在程序启动的时候编译器会调用Point的合成的默认构造函数来初始化global变量,在程序退出时会调用Point的合成的析构函数来销毁global变量。实际上,C++编译器会将Point看成是一个POD对象,既不会调用合成的构造函数也不会调用合成的析构函数,但C++编译器会将global当成初始化过的数据来对待,不放入BSS段。

foobar函数中的local局部变量不会自动初始化,意味着local.x中的值是不可控的,但是local变量分配了栈空间。

*heap = local;执行时仅简单执行按字节复制操作,不会产生赋值操作符,因为Point是一个POD类型。

return local;同样仅通过字节复制操作产生一个临时对象。

抽象数据类型

这次将上面的Point类型从struct变换为class

1
2
3
4
5
6
7
8
class Point
{
public:
Point(float x=0.0, float y=0.0, float z=0.0) : _x(x), _y(y), _z(z){}

private:
float _x, _y, _z;
};

在上节中的foobar函数中,各个对象的默认复制构造函数、赋值操作符和析构函数仍然不会调用,因为调用是没有意义的,因此编译器干脆就不产生。

为继承做准备

再次更改Point类,引入虚函数。

1
2
3
4
5
6
7
8
class Point
{
public:
Point(float x=0.0, float y=0.0) : _x(x), _y(y) {}
virtual float z();
private:
float _x, _y;
};

引入虚函数后,类对象就需要一个vtbl来存放虚函数的地址,类对象中需要添加vptr指针。而vptr的初始化是在对象构造的时候,因此对象初始化的时候需要调用构造函数,同时默认构造函数和赋值构造函数会自动在构造函数的最前面插入初始化vptr的代码。

继承体系下的对象构造

C++时会自动扩充类的每一个构造函数。扩充步骤如下:

  1. 如果类含有虚基类,则所有虚基类的构造函数被调用,调用顺序为从左到右,从最深到最浅。
  2. 如果类含有基类,则基类构造函数会被调用,以基类的声明顺序为顺序。
  3. 如果类对象中含有vptr,必须在初始化类的成员变量之前为vptr指定初值,使其指向vtbl。
  4. 将成员初始化列表中数据成员的初始化操作放入构造函数内部,并且按照成员在类中的声明顺序。
  5. 如果类成员变量不在构造函数的初始化列表中,但是成员变量含有默认构造函数,则默认构造函数必须被调用。

虚拟继承

本小节将学习一下引入了虚继承机制之后构造函数的生成是什么样子的。

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
33
34
35
class Point
{
public:
Point(float x=0.0, float y=0.0) : _x(x), _y(y) {}
virtual float z();
private:
float _x, _y;
};

class Point3d : public virtual Point
{
public:
Point3d(float x=0.0, float y=0.0, float z=0.0)
: Point(x, y), _z(z) {}
~Point3d();

virtual float z() {return _z;}
protected:
float _z;
};

class Vertex : virtual public Point
{
// 不是重点忽略
};

class Vertex3d : public Point3d, public Vertex
{
// 不是重点忽略
};

class PVertex : public Vertex3d
{
// 不是重点忽略
};

类之间的继承关系如下图所示,已经属于最复杂的继承模型了。
Image Title
如果要构造Vertex3d的实例,在内存中必须仅能有一个Point类型的对象,而如果在Point3d和Vertex基类中都构造一个Point实例显然是不合适的。答案是编译器会在Vertex3d的构造函数中生成Point的对象,在Point3d和Vertex的构造函数中均不会生成Point的对象。Vertex3d和Point3d的构造函数伪码如下面所示,Vertex构造函数的伪码和Point3d类似,这里就不再列出。

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
Point3d* Point3d::Point3d(Point3d *this, bool __most_derived, float x, float y, float z)
{
// 如果子类初始化基类则本构造函数不需要初始化基类
if (__most_derived != false)
{
this->Point::Point(x, y);
}
this->__vptr_Point3d = __vtbl_Point3d; // 初始化指向本类的vptr
this->__vptr_Point3d_Point = __vtbl_Point3d_Point; // 初始化指向基类的vptr
this->_z = z;
return *this;
}

Vertex3d* Vertex3d::Vertex3d(Vertex3d *this, bool __most_derived, float x, float y, float z)
{
if (__most_derived != false)
{
this->Point::Point(x, y);
}
this->Point3d::Point3d(false, x, y, z);
this->Vertex::Vertex(false, x, y);
// 初始化vptr
// 用户代码
return this;
}

编译器在类的构造函数中增加了一个bool变量来判断本类是否需要初始化基类,虚基类的初始化始终在继承最底层的类构造函数中初始化。对于PVertex类来说,Point类的构造函数在该类的构造函数中调用。

vptr初始化语意学

vptr的在构造函数中的初始化时机为:在基类构造函数调用操作之后,在成员初始化列表和构造函数中显式代码之前。
构造函数的执行先后顺序为:

  1. 所有虚基类、基类的构造函数会被调用。
  2. 对象的vptr初始化,指向相关的vtbl。
  3. 在构造函数内展开成员的初始化列表。
  4. 执行显式代码。

对象复制语意学

没有一成不坏的硬件,尤其是数据放到物理硬盘中,说不定哪天硬盘闹脾气就崩掉了,硬盘不值钱,可是里面的数据值钱。下面分享下我的数据备份方案,我的原则是数据无论何时都至少留有一个备份。

博客

我的博客是放到Dropbox中的,在云端和本地均有备份,确保了博客数据的绝对安全,即使云端坏掉还有本地,本地丢了还有云端。

个人照片

由于照片都较大,放到本地硬盘很容易占满空间,而且还不经常用。除了在自己电脑上留有照片之外,选择将照片压缩并加密后按照年份放到百度云上。

代码

工作几年了,已经积攒了一些代码,有些代码时不时的会查看到。对于可以公开的自己写的代码我以后打算放到我的Github上,一方面是由于Github上可以在线浏览代码,另一方面可以向别人分享我的代码。
对于私有的代码,暂时放到了金山快盘上,没有找到可以方便浏览代码的云端。

文档

由于文档之类的资料也是经常用到,我选择了金山快盘。

大小端问题跟CPU的架构直接相关,我们常见的80x86系列CPU采用小端字节序模式。Windows平台就采用的80x86系列CPU,因此为小端字节序。
而主机之间进行网络通信时往往采用大端字节序,因此小端字节序机器在发送数据前需要进行字节序转换,在接收到数据处理处理数据之前要将网络字节序转换成本地字节序。

在Linux平台下提供了四个函数用来字节序转换:

1
2
3
4
5
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

Windows平台下也提供了相关的自己序转换函数:

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
33
34
35
36
37
38
39
40
41
42
#include <WinSock2.h>
unsigned __int64 __inline htond(
double value
);

unsigned __int32 __inline htonf(
float value
);

u_long WSAAPI htonl(
_In_ u_long hostlong
);

unsigned __int64 __inline htonll(
unsigned __int64 value
);

u_short WSAAPI htons(
_In_ u_short hostshort
);


double __inline ntohd(
unsigned __int64 value
);

float __inline ntohf(
unsigned __int32 value
);

u_long WSAAPI ntohl(
_In_ u_long netlong
);

u_long __inline ntohll(
unsigned __int64 value
);

u_short WSAAPI ntohs(
_In_ u_short netshort
);

这里有个技巧需要说明以下,比如要发送如下的结构体:

1
2
3
4
5
struct foo
{
int a;
long b;
};

为了避免每个成员都调用字节序转换函数,可以在结构体的内部定义两个方法用于转换字节序,添加字节序后的foo如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct foo
{
int a;
long b;
void ntoh()
{
a = ntohl(a);
b = ntohl(b);
}
void hton()
{
a = htonl(a);
b = htonl(b);
}
};

需要特别注意的是,在发送结构体类型的数据时要注意字节对齐的问题,这里不再展开讨论,不同的平台有不同的解决办法。大体分为Winodws平台、AIX平台和GNU类平台。

近段时间写了两个通过http协议来获取指定网页的内容并将内容解析出来的程序。程序一可以解析出目前本博客的内容页面的内容、时间、访问次数参数,采用Qt类库实现;程序二可以解析出新浪博客页面的内容、时间等参数,采用Linux下的tcp相关API实现。均采用C++语言实现。

程序一

该程序采用Qt类库实现,其中Http协议的发送和接收采用Qt类库封装的类,网页内容的解析采用Qt封装的解析XML的相关类。
该程序仅能解析标准的Html语言,对于网页中的所有”<>”标签必须有结尾才行。例如本页面源码中的

1
<meta content="black" name="apple-mobile-web-app-status-bar-style" />

必须是闭合的。如果是下面这样则无法正确解析网页内容,这是由于采用的Qt类库决定的。

1
<meta content="black" name="apple-mobile-web-app-status-bar-style">

程序二

该程序的Http协议部分采用Linux的tcp协议api实现,解析网页直接采用搜索字符串的方式实现,较上一种方式要底层,仅能运行在Linux系统下运行。

相关下载

程序一和二的下载链接

本文的安装环境为ubuntu13.04。为了以后便于查阅,本文将相关插件的使用放到了文章的开始部分。这里不作插件的相关介绍,相关介绍看文章底部的参考文章。

插件使用

本插件快捷键会跟随下文安装内容一块同步。

ctags

在源码目录执行ctags -R可生成ctags文件。该文件在源码修改后并不会改变,需要重新生成ctags文件。
ctrl+]:转到函数定义处。
ctrl+T:回到执行ctrl+]的地方。

taglist

:TlistOpen:打开taglist窗口
:TlistClose:关闭taglist窗口。
:TlistToggle:在打开和关闭间切换。

NERD tree

:NERDTree:打开窗口。

winmanager

wm:打开和关闭taglist和NERD tree窗口。

a.vim

:A:在新Buffer中切换到c/h文件
:AS:横向分割窗口并打开c/h文件
:AV:纵向分割窗口并打开c/h文件
:AT:新建一个标签页并打开c/h文件
F12:代替:A命令

MiniBufExplorer

<Tab>:向前循环切换到每个buffer名上
<S-Tab>:向后循环切换到每个buffer名上
<Enter>:在打开光标所在的buffer
d:删除光标所在的buffer

插件安装

安装ctags

执行: sudo apt-get install ctags

安装taglist

  1. 下载页面:http://www.vim.org/scripts/script.php?script_id=273。下载后得到taglist_46.zip文件。
  2. 执行unzip taglist_46.zip解压文件。
  3. 将解压出的文件复制到~/.vim目录下。sudo cp ~/tmp/ ~/.vim/
  4. 在~/.vimrc文件中添加如下:
    1
    2
    3
    let Tlist_Show_One_File = 1            "不同时显示多个文件的tag,只显示当前文件的
    let Tlist_Exit_OnlyWindow = 1 "如果taglist窗口是最后一个窗口,则退出vim
    let Tlist_Use_Right_Window = 1 "在右侧窗口中显示
    参考网址:http://www.cnblogs.com/mo-beifeng/archive/2011/11/22/2259356.html

安装文件浏览器NERD tree

  1. 下载页面:http://www.vim.org/scripts/script.php?script_id=1658。
  2. 将下载后的nerdtree.zip文件解压到~/.vim目录下。

安装winmanager

  1. 下载页面:http://www.vim.org/scripts/script.php?script_id=95
  2. 将下载后的winmanager.zip文件解压到~/.vim目录下
  3. 修改.vimrc文件,添加:
    1
    2
    let g:winManagerWindowLayout='FileExplorer|TagList'
    nmap wm :WMToggle<cr>
    这样利用winmanager工具将taglist和NERD tree工具整合到了一个块,输入wm可以打开和关闭窗口。

安装cscope

  1. 下载页面:http://cscope.sourceforge.net,下载后得到文件cscope-15.8a.tar.gz。
  2. ./configure
  3. make。可能会出现错误,执行如下命令:
    1
    2
    3
    apt-get install libncurses-dev
    sudo apt-get install flex
    sudo apt-get install byacc
    然后执行make clean后重新make。
  4. sudo make install

安装在h/c文件之间切换插件a.vim

  1. 下载页面:http://www.vim.org/scripts/script.php?script_id=31。
  2. 将下载的a.vim文件复制到~/.vim/plugin文件夹下。
  3. 在~/.vimrc文件中添加nnoremap <silent> <F12> :A<CR>
  4. 下面内容为快捷键列表:
    :A switches to the header file corresponding to the current file being edited (or vise versa)
    :AS splits and switches
    :AV vertical splits and switches
    :AT new tab and switches
    :AN cycles through matches
    :IH switches to file under cursor
    :IHS splits and switches
    :IHV vertical splits and switches
    :IHT new tab and switches
    :IHN cycles through matches
    ih switches to file under cursor
    is switches to the alternate file of file under cursor (e.g. on <foo.h> switches to foo.cpp)
    ihn cycles through matches

安装快速浏览和操作Buffer

  1. 下载页面:http://www.vim.org/scripts/script.php?script_id=159
  2. 将下载的 minibufexpl.vim文件丢到 ~/.vim/plugin 文件夹中即可
  3. 在~/.vimrc文件中增加如下行:
    1
    2
    3
    let g:miniBufExplMapCTabSwitchBufs = 1
    let g:miniBufExplMapWindowNavVim = 1
    let g:miniBufExplMapWindowNavArrows = 1
  4. 快捷键:
    向前循环切换到每个buffer名上
    向后循环切换到每个buffer名上
    在打开光标所在的buffer
    d 删除光标所在的buffer

参考文章

Image Title

前段时间在家看书学习,难得的学习的好时机。

楼下有一个卖饭的小摊及其猖狂,不仅占用了人行道来炒菜,而且还在马路上摆了一溜桌子供客人吃饭,不仅占用了人行道,连车行道都给占用了。这些也就罢了,对我影响都不算太大,更可气的是每天中午和晚上吃饭的时候会开着大音响放着恼人的音乐,我不想惹麻烦,我忍。

今天中午我刚开始看书,看到难处需要精心思考,恼人的音乐又开始了,我实在忍不住了,TMD,维权。打市长热线12345投诉,市长热线让我打110投诉。继续打110投诉,然后跟110说了下具体情况后,说给相应的派出所去处理。派出所的小片警立刻就给我回电话了,说外放音乐正常经营范围,只要不在晚上或清晨放音乐就不算违规,他们管不着,建议我去下面跟卖饭的商量,好一个商量。然后我又说,他们非法占道经营,小片警又说这个归城管管,让我给城管打电话,好一个给城管打电话。好一个推卸责任,这些把我给惹毛了。

挂断电话后,寻思这个理不太对,然后继续给市长热线12345打电话,告诉情况后,市长热线的妹子告诉我说这个事情我给你处理,好一个我给你处理,这才是为人民服务的态度,鼓掌。

这是第二次机会接触小片警,每次都是让我失望,绝望,恨之入骨。第一次接触小片警我甚至kill him的心都有了。不一心想着为人民服务,却是一心想着推卸责任,处处刁难市民并从中谋取私利,对市民爱理不理,这就是小片警在我心中的形象,很难改变。越是权利小的小兵,架子越大,这也就决定了永远是个小兵的身份。

如果没有市长热线那这件扰民的事情也就不了了之了,因为投诉110都不管用了,作为市民已经没有可以维权的机构了。还好有市长热线的存在给市民多了一个维权的途径。

上周五打的电话,这个周一给我回复电话问我饭馆在哪一次,周二又打电话问我饭馆在哪,然后周三终于给处理了,下班途中派出所给我电话回复说:“已经处理好了,让小饭馆的音响声音调小了,以后如果再有这种情况可以继续打电话”。等我回家一看,果然音响不见了,世界一下子清净了,zf终于替我办事了。

也许是因为我的事情不是很紧急的原因,整个处理流程过于慢了,等了足足五天的时间才处理好。

当大家的权益受到损害时,请大家多给市长热线打电话维护自己的权益。

Image Title

得知老家三老爷家的三叔去世了,原本还在看代码的我收到消息之后立刻无法平静了,只好出去走走散散心,回家之后依然感觉莫名的胸闷,玩游戏分散分散精力,游戏过后依然胸闷。意料之中的失眠,中途醒了好几次。总感觉消息不是真实的,总感觉昨晚在梦中,真希望一觉醒来之后什么都没有发生。

三叔42岁,正值壮年,在家附近的号称有一万员工的炼钢厂打工,在整个市也算是很大的企业了。工作中意外丧命。总觉得这样的事情不会发生在我身边,客观事实是发生了。

听家人说,三叔小时候调皮爬到树上掏鸟窝从树上掉下来把一个肩膀都磕到身体里了,大家都觉得肯定好不了,在镇上医院住院打吊瓶打够了自己偷偷跑回学校,后来居然奇迹般的好了,而且还没留下任何痕迹。大家都说三叔命大,谁知三叔小时候躲过了一劫却没有躲过这一劫,这难道就是天命?三叔一生勤俭节约,人忠厚老实,到头来却落得如此下场,谁说上帝是公平的,谁说好人有好报,这都是胡扯。

临近三叔出事的前天,我做了一个很不好的梦,梦的内容我已经记不起来了。回家后听家里人说很多人都做了不好的梦,甚至连平常不怎么做梦的都会被梦惊醒。这绝对不是巧合,很明显已经超出了当前科学的范畴。

记得最后一次跟三叔接触还是在过年的时候,三叔到我家来转转,聊了几句,现在还记忆犹新。再上一次见面就是在去年夏天的一个下午,约着三婶去火车站接三叔家的弟弟和我爸,正巧在三叔家的门口碰到三叔,估计是要去上夜班。

每年过年我们一大家20多人就会团聚在一起,男人一桌,女人一桌,还有我们小孩一桌,其乐融融。最近两年过年三叔是唯一缺席的,由于工作的原因,三叔正巧在过年的时候上夜班。总觉得少了三叔过年的时候是个遗憾,现在看来以后过年要永远遗憾下去了。

企业在追求经济效益的同时,往往会忽略员工的安全。员工伤亡事件屡见不鲜,却很难得到企业的重视。相比人类的伤亡,企业的经济效益显得那么苍白无力。听说钢厂每年总会出些事故,但是事故的赔偿是从所有员工的工资中扣除的,而不是工厂承担,这也是工厂对安全问题不够重视的原因,反正出了事掉血的是员工。

现在村中的人大部分出去在外面打工,农忙时回家忙几天。在此提醒相亲们一定要注意人身安全,没有了安全保障赚再多的钱都白搭。

谨以此文献给为工作而献身的三叔。

0%