前言
今天向工程中添加了一个.h, 里面包含了一个结构, 结构中定义了运算符(> <)重载. 没特别的, 在debian8 + c++98下编译不过。实在没看出来是哪里有问题. 于是将.h分成了.h +.cpp, 这回,编译器报错的定位容易找了。找到以下问题:
在一个函数的条件判断中,少加了后面的括弧
stl::map中用类或结构作为key时, 类中要重载 < 运算符
重载的运算符要有const限定
e.g. bool operator < (const TAG_IP_ADDR_ARY& src) const;在const限定的成员函数中调用的其他成员函数, 也必须有const限定
e.g. bool is_ipv4() const;
对于较简单的结构或类, 将内容都写入.h, 用起来是方便,但是如果编译不过,报错点也不太好找,眼神要特别的好。
demo工程下载点
src_test_class_operator_overload.7z
实验
// @file main.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h> // daemon
#include <signal.h>
#include <time.h>
#include <map>
#include "my_syslog.h"
#include "TAG_IP_ADDR_ARY.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) \
if (NULL != (p)) { \
delete (p); \
(p) = NULL; \
}
#endif // #ifndef SAFE_DELETE
#define LINE80 "--------------------------------------------------------------------------------"
void init(const char* psz_log_owner_name);
void uninit();
void proc_sig_term(int num);
int fn_test();
int main(int argc, char** argv)
{
char sz_buf[1024] = {'\0'};
#ifdef MAKE_FILE_MACRO__BIN_NAME
sprintf(sz_buf, "%s", MAKE_FILE_MACRO__BIN_NAME);
init(sz_buf);
MYLOG_D("MAKE_FILE_MACRO__BIN_NAME = [%s]", MAKE_FILE_MACRO__BIN_NAME);
#else
init(NULL);
#endif // #ifdef MAKE_FILE_MACRO__BIN_NAME
fn_test();
uninit();
MYLOG_D("THE END");
return EXIT_SUCCESS;
}
int fn_test()
{
MYLOG_D(">> fn_test()");
TAG_IP_ADDR_ARY ipv4_a;
TAG_IP_ADDR_ARY ipv4_b;
TAG_IP_ADDR_ARY ipv6_a;
TAG_IP_ADDR_ARY ipv6_b;
uchar sz_ip[16] = {
0xaa, 0xab, 0xba, 0xbb,
0xaa, 0xab, 0xba, 0xbb,
0xaa, 0xab, 0xba, 0xbb,
0xaa, 0xab, 0xba, 0xbb};
ipv4_a.set_ipv4(0xaabbccdd);
ipv4_b.set_ipv4(0xaabbccee);
ipv6_a.set_ipv6(sz_ip, sizeof(sz_ip));
sz_ip[14] = 0xaa;
ipv6_b.set_ipv6(sz_ip, sizeof(sz_ip));
// case ipv4
printf("%s\n", LINE80);
if (ipv4_a > ipv4_b) {
printf("ipv4_a > ipv4_b\n");
}
if (ipv4_a >= ipv4_b) {
printf("ipv4_a >= ipv4_b\n");
}
if (ipv4_a < ipv4_b) {
printf("ipv4_a < ipv4_b\n");
}
if (ipv4_a <= ipv4_b) {
printf("ipv4_a <= ipv4_b\n");
}
if (ipv4_a == ipv4_b) {
printf("ipv4_a == ipv4_b\n");
}
if (ipv4_a != ipv4_b) {
printf("ipv4_a != ipv4_b\n");
}
// case ipv6
printf("%s\n", LINE80);
if (ipv6_a > ipv6_b) {
printf("ipv6_a > ipv6_b\n");
}
if (ipv6_a >= ipv6_b) {
printf("ipv6_a >= ipv6_b\n");
}
if (ipv6_a < ipv6_b) {
printf("ipv6_a < ipv6_b\n");
}
if (ipv6_a <= ipv6_b) {
printf("ipv6_a <= ipv6_b\n");
}
if (ipv6_a == ipv6_b) {
printf("ipv6_a == ipv6_b\n");
}
if (ipv6_a != ipv6_b) {
printf("ipv6_a != ipv6_b\n");
}
// case ipv4 and ipv6
// 不同类型的数据是没有必要比较的, 这个测试没意义
printf("%s\n", LINE80);
if (ipv4_a > ipv6_b) {
printf("ipv4_a > ipv6_b\n");
}
if (ipv4_a >= ipv6_b) {
printf("ipv4_a >= ipv6_b\n");
}
if (ipv4_a < ipv6_b) {
printf("ipv4_a < ipv6_b\n");
}
if (ipv4_a <= ipv6_b) {
printf("ipv4_a <= ipv6_b\n");
}
if (ipv4_a == ipv6_b) {
printf("ipv4_a == ipv6_b\n");
}
if (ipv4_a != ipv6_b) {
printf("ipv4_a != ipv6_b\n");
}
// case map key use class
printf("%s\n", LINE80);
std::map<TAG_IP_ADDR_ARY, int> map_ip;
std::map<TAG_IP_ADDR_ARY, int>::iterator it;
map_ip.insert(std::make_pair(ipv4_a, 1));
it = map_ip.find(ipv4_a);
if (it != map_ip.end()) {
printf("find ipv4_a\n");
}
it = map_ip.find(ipv6_a);
if (it != map_ip.end()) {
printf("find ipv6_a\n");
}
return 0;
}
/** run result
--------------------------------------------------------------------------------
ipv4_a < ipv4_b
ipv4_a <= ipv4_b
ipv4_a != ipv4_b
--------------------------------------------------------------------------------
ipv6_a > ipv6_b
ipv6_a >= ipv6_b
ipv6_a != ipv6_b
--------------------------------------------------------------------------------
ipv4_a < ipv6_b
ipv4_a != ipv6_b
--------------------------------------------------------------------------------
find ipv4_a
*/
void init(const char* psz_log_owner_name)
{
int i = 0;
// daemon(0, 0);
ns_syslog::open_syslog((NULL != psz_log_owner_name) ? psz_log_owner_name : "ns_syslog");
ns_syslog::g_log_condition.b_EMERG = false;
ns_syslog::g_log_condition.b_CRIT = true;
ns_syslog::g_log_condition.b_ALERT = true;
ns_syslog::g_log_condition.b_ERR = true;
ns_syslog::g_log_condition.b_WARNING = true;
ns_syslog::g_log_condition.b_NOTICE = true;
ns_syslog::g_log_condition.b_INFO = true;
ns_syslog::g_log_condition.b_DEBUG = true;
ns_syslog::set_log_level(
ns_syslog::g_log_condition.b_EMERG,
ns_syslog::g_log_condition.b_ALERT,
ns_syslog::g_log_condition.b_CRIT,
ns_syslog::g_log_condition.b_ERR,
ns_syslog::g_log_condition.b_WARNING,
ns_syslog::g_log_condition.b_NOTICE,
ns_syslog::g_log_condition.b_INFO,
ns_syslog::g_log_condition.b_DEBUG);
// clear screen (print 25 empty line)
for (i = 0; i < 25; i++) {
MYLOG_D("");
}
signal(SIGTERM, proc_sig_term);
}
void uninit()
{
ns_syslog::close_syslog();
}
void proc_sig_term(int num)
{
MYLOG_D("SIGTERM = %d, num = %d", SIGTERM, num);
MYLOG_D("maybe can do some clean task before quit");
exit(1);
}
// @file \src\TAG_IP_ADDR_ARY.h
#ifndef __TAG_IP_ADDR_ARY_H__
#define __TAG_IP_ADDR_ARY_H__
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>
#ifndef uchar
typedef unsigned char uchar;
#endif // #ifndef uchar
#pragma pack(push)
#pragma pack(1)
// 像使用结构一样使用类
// 要像结构一样的保存类的内容(基本数据类型), 不能有虚表
class TAG_IP_ADDR_ARY {
public:
// 没有一种内建数据类型能表示128bits, 所以用char[16]数组来表示ipv6的ip地址
uchar ip_ary[16];
uint u_hash;
TAG_IP_ADDR_ARY();
~TAG_IP_ADDR_ARY(); // non virtual deconsturct fun
// 运算符参数重载时, 如果使用了stl中的find(间接), 那么运算符重载要有const限定
// 在const限定的成员函数中调用其他成员函数, 那些成员函数也要有const限定
bool operator < (const TAG_IP_ADDR_ARY& src) const;
bool operator <= (const TAG_IP_ADDR_ARY& src) const;
bool operator > (const TAG_IP_ADDR_ARY& src) const;
bool operator >= (const TAG_IP_ADDR_ARY& src) const;
bool operator != (const TAG_IP_ADDR_ARY& src) const;
bool operator == (const TAG_IP_ADDR_ARY& src) const;
// member function imp, all member function not allow to virtual
bool is_valid() const;
bool is_ipv4() const;
void clear();
void set_ipv4(uint u_ipv4);
void set_ipv6(uchar* psz_ipv6, int len_ipv6);
void set_ip(const char* psz_ip);
std::string to_string() const;
uint ipv4_to_uint();
std::string ipv6_to_string();
uint elf_hash(uchar* buf, int len);
void calc_hash();
uint hash();
// '0'~'9' 'a'~'f' 'A'~'F' to 0~15
uchar get_ascii_char_value(char c_in);
};
#pragma pack(pop)
#endif // #ifndef __TAG_IP_ADDR_ARY_H__
// @file \src\TAG_IP_ADDR_ARY.cpp
#include "TAG_IP_ADDR_ARY.h"
TAG_IP_ADDR_ARY::TAG_IP_ADDR_ARY() {
clear();
}
TAG_IP_ADDR_ARY::~TAG_IP_ADDR_ARY() {
clear();
}
void TAG_IP_ADDR_ARY::clear() {
memset(ip_ary, 0, sizeof(ip_ary));
calc_hash(); // 只有在数据初始化或设置新值时, 计算一次hash
}
void TAG_IP_ADDR_ARY::set_ipv4(uint u_ipv4) {
clear();
// copy u_ipv4 to ip[12] ~ ip[15]
memcpy((ip_ary + 12), &u_ipv4, sizeof(uint));
calc_hash(); // 只有在数据初始化或设置新值时, 计算一次hash
}
void TAG_IP_ADDR_ARY::set_ipv6(uchar* psz_ipv6, int len_ipv6) {
clear();
if ((NULL == psz_ipv6) || ((int)sizeof(ip_ary) != len_ipv6)) {
return;
}
memcpy(ip_ary, psz_ipv6, len_ipv6);
calc_hash(); // 只有在数据初始化或设置新值时, 计算一次hash
}
void TAG_IP_ADDR_ARY::set_ip(const char* psz_ip) {
int i = 0;
size_t nlen = 0;
uchar uc_tmp[16];
uchar uc_now = '\0';
char c_tmp = '\0';
uint u_ipv4 = 0;
uchar ip_ary[16] = {'\0'};
int pos_index = 0;
int ary_index = 0;
memset(uc_tmp, 0, sizeof(uc_tmp));
if (NULL == psz_ip) {
return;
}
nlen = sizeof(psz_ip);
if (NULL != strchr(psz_ip, '.')) {
// ipv4 string
// 192.168.4.11
u_ipv4 = 0;
uc_now = 0;
for (i = 0; i < (int)nlen; i++) {
c_tmp = psz_ip[i];
if ('.' == c_tmp) {
u_ipv4 <<= 8;
u_ipv4 += uc_now;
uc_now = 0;
continue;
} else {
uc_now *= 10;
uc_now += get_ascii_char_value(c_tmp);
}
}
set_ipv4(u_ipv4);
} else if (NULL != strchr(psz_ip, ':')) {
// 在实现都在.h中实现时
// 有编译报错时, 上面的条件右面少了一个')', 导致编译的时候各种错
// 因为找不到是哪里有问题, 拆开成.h, .cpp实现, 这时编译器报错信息就比较好定位了
// ipv6 string
// fd15:4ba5:5a2b:1002:20c:29ff:fe89:e2cd
uc_now = 0;
pos_index = 0;
memset(ip_ary, 0, sizeof(ip_ary));
for (i = 0; i < (int)nlen; i++) {
c_tmp = psz_ip[i];
if (':' == c_tmp) {
continue;
} else {
uc_now <<= 4;
uc_now += get_ascii_char_value(c_tmp);
pos_index++;
if (2 == pos_index) {
if (ary_index < (int)sizeof(ip_ary)) {
ip_ary[ary_index++] = uc_now;
}
uc_now = 0;
}
}
}
set_ipv6(ip_ary, (int)sizeof(ip_ary));
}
}
bool TAG_IP_ADDR_ARY::is_valid() const {
// 是否有效
// 如果不为全0, 就有效
int i = 0;
const uint zero = 0;
for (i = 0; i < 4; i++) {
if (0 != memcmp(ip_ary + i * sizeof(uint), &zero, sizeof(uint))) {
return true; // 非空为有效
}
}
return false;
}
bool TAG_IP_ADDR_ARY::is_ipv4() const {
// 前12个字节为0, 就是ipv4
int i = 0;
const uint zero = 0;
for (i = 0; i < 3; i++) {
if (0 != memcmp(ip_ary + i * sizeof(uint), &zero, sizeof(uint))) {
return false; // 非空为ipv6
}
}
return true;
}
std::string TAG_IP_ADDR_ARY::to_string() const {
std::string rc = "";
char sz_buf[0x100] = {'\0'};
if (is_valid()) {
if (is_ipv4()) {
sprintf(sz_buf,
"%d.%d.%d.%d%c",
ip_ary[12], ip_ary[13], ip_ary[14], ip_ary[15],
'\0');
} else {
sprintf(sz_buf,
"%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X%c",
ip_ary[0], ip_ary[1], ip_ary[2], ip_ary[3],
ip_ary[4], ip_ary[5], ip_ary[6], ip_ary[7],
ip_ary[8], ip_ary[9], ip_ary[10], ip_ary[11],
ip_ary[12], ip_ary[13], ip_ary[14], ip_ary[15],
'\0');
}
rc = sz_buf;
}
return rc;
}
std::string TAG_IP_ADDR_ARY::ipv6_to_string()
{
std::string rc = "";
char sz_buf[0x100] = {'\0'};
if (is_valid()) {
if (is_ipv4()) {
} else {
sprintf(sz_buf,
"%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X%c",
ip_ary[0], ip_ary[1], ip_ary[2], ip_ary[3],
ip_ary[4], ip_ary[5], ip_ary[6], ip_ary[7],
ip_ary[8], ip_ary[9], ip_ary[10], ip_ary[11],
ip_ary[12], ip_ary[13], ip_ary[14], ip_ary[15],
'\0');
}
rc = sz_buf;
}
return rc;
}
uint TAG_IP_ADDR_ARY::ipv4_to_uint()
{
uint rc = 0;
if (is_valid() && is_ipv4()) {
rc = *(uint*)&ip_ary[12];
}
return rc;
}
uint TAG_IP_ADDR_ARY::elf_hash(uchar* buf, int len)
{
// elf hash alg
uint rc = 0;
uint x = 0;
if (NULL == buf) {
return rc;
}
while (len > 0)
{
rc = (rc << 4) + *buf;
x = rc & 0xf0000000;
if (0 != x) {
rc ^= (x >> 24); // 影响5-8位, 杂糅一次
rc &= ~x; // 清空高四位
}
buf++;
len--;
}
return (rc & 0x7fffffff);
}
void TAG_IP_ADDR_ARY::calc_hash()
{
u_hash = elf_hash(ip_ary, (int)sizeof(ip_ary));
}
uint TAG_IP_ADDR_ARY::hash()
{
return u_hash;
}
bool TAG_IP_ADDR_ARY::operator < (const TAG_IP_ADDR_ARY& src) const {
int i = 0;
if (!this->is_valid() || !src.is_valid()) {
return false;
}
if (this->is_ipv4() && src.is_ipv4()) {
// 按照ipv4比对
for (i = 12; i <= 15; i++) {
if (this->ip_ary[i] < src.ip_ary[i]) {
return true;
} else if (this->ip_ary[i] > src.ip_ary[i]) {
return false;
}
}
} else {
// 按照ipv6比对
for (i = 0; i <= 15; i++) {
if (this->ip_ary[i] < src.ip_ary[i]) {
return true;
} else if (this->ip_ary[i] > src.ip_ary[i]) {
return false;
}
}
}
return false;
}
bool TAG_IP_ADDR_ARY::operator <= (const TAG_IP_ADDR_ARY& src) const {
int i = 0;
if (!this->is_valid() || !src.is_valid()) {
return false;
}
if (this->is_ipv4() && src.is_ipv4()) {
// 按照ipv4比对
for (i = 12; i <= 15; i++) {
if (this->ip_ary[i] > src.ip_ary[i]) {
return false;
}
}
} else {
// 按照ipv6比对
for (i = 0; i <= 15; i++) {
if (this->ip_ary[i] > src.ip_ary[i]) {
return false;
}
}
}
return true;
}
bool TAG_IP_ADDR_ARY::operator > (const TAG_IP_ADDR_ARY& src) const {
int i = 0;
if (!this->is_valid() || !src.is_valid()) {
return false;
}
if (this->is_ipv4() && src.is_ipv4()) {
// 按照ipv4比对
for (i = 12; i <= 15; i++) {
if (this->ip_ary[i] > src.ip_ary[i]) {
return true;
} else if (this->ip_ary[i] < src.ip_ary[i]) {
return false;
}
}
} else {
// 按照ipv6比对
for (i = 0; i <= 15; i++) {
if (this->ip_ary[i] > src.ip_ary[i]) {
return true;
} else if (this->ip_ary[i] < src.ip_ary[i]) {
return false;
}
}
}
return false;
}
bool TAG_IP_ADDR_ARY::operator >= (const TAG_IP_ADDR_ARY& src) const {
int i = 0;
if (!this->is_valid() || !src.is_valid()) {
return false;
}
if (this->is_ipv4() && src.is_ipv4()) {
// 按照ipv4比对
for (i = 12; i <= 15; i++) {
if (this->ip_ary[i] < src.ip_ary[i]) {
return false;
}
}
} else {
// 按照ipv6比对
for (i = 0; i <= 15; i++) {
if (this->ip_ary[i] < src.ip_ary[i]) {
return false;
}
}
}
return true;
}
bool TAG_IP_ADDR_ARY::operator != (const TAG_IP_ADDR_ARY& src) const {
int i = 0;
if (!this->is_valid() || !src.is_valid()) {
return false;
}
if (this->is_ipv4() && src.is_ipv4()) {
// 按照ipv4比对
for (i = 12; i <= 15; i++) {
if (this->ip_ary[i] != src.ip_ary[i]) {
return true;
}
}
} else {
// 按照ipv6比对
for (i = 0; i <= 15; i++) {
if (this->ip_ary[i] != src.ip_ary[i]) {
return true;
}
}
}
return false;
}
bool TAG_IP_ADDR_ARY::operator == (const TAG_IP_ADDR_ARY& src) const {
int i = 0;
if (!this->is_valid() || !src.is_valid()) {
return false;
}
if (this->is_ipv4() && src.is_ipv4()) {
// 按照ipv4比对
for (i = 12; i <= 15; i++) {
if (this->ip_ary[i] != src.ip_ary[i]) {
return false;
}
}
return true;
} else {
// 按照ipv6比对
for (i = 0; i <= 15; i++) {
if (this->ip_ary[i] != src.ip_ary[i]) {
return false;
}
}
return true;
}
return false;
}
// '0'~'9' 'a'~'f' 'A'~'F' to 0~15
uchar TAG_IP_ADDR_ARY::get_ascii_char_value(char c_in)
{
if ((c_in >= '0') && (c_in <= '9')) {
return (uchar)(c_in - '0');
} else if ((c_in >= 'a') && (c_in <= 'f')) {
return (uchar)(c_in - 'a' + 10);
} else if ((c_in >= 'A') && (c_in <= 'F')) {
return (uchar)(c_in - 'A' + 10);
} else {
return 0;
}
}