嵌入式Linux开发的编程语言选择

嵌入式Linux开发的编程语言选择欢迎大家关注我的公 号 embedded bug 这里的嵌入式 Linux 环境是指非标准 Linux 发行版环境 比如通过 buildroot 创建的 相比于标准的 Linux 发行版比如 ubuntu debian fedora 系统比较简陋 提供的库很有限

大家好,我是讯享网,很高兴认识大家。

欢迎大家关注我的公*号:embedded_bug

这里的嵌入式Linux环境是指非标准Linux发行版环境,比如通过buildroot创建的,相比于标准的Linux发行版比如ubuntu,debian,fedora,系统比较简陋,提供的库很有限,而且系统的各种配置文件和配置方式与标准Linux发行版差别很大,总之,这里的嵌入式Linux只保证系统能够基本的启动运行起来。

在这里插入图片描述
讯享网

上图是现在编程语言的流行度排名,别看这么多语言,真正适合在嵌入式Linux中应用的并不多。

直接说结论,个人推荐:go>C++(11)+boost>c,其他语言目前还都不太适合。

本篇文章先讨论C和C++,下面一篇文章讨论go及其他语言。

一、C语言,迫不得已的选择

​ C语言作为最基本的编程语言,只要是个嵌入式Linux环境肯定都是支持的,但是同样使用C的问题很多,包括:

  • 语言比较老旧,很多高级语言的特性比较缺乏,程序写起来比较费时间,容易出错,代码行数也多。
  • 基础C库功能太少,需要什么新功能还得去找相当的函数库,然后交叉编译,测试函数库功能怎么样,是否满足需求,费时费力。

    总之,C语言的问题是库少,写起来费事,容易出错。优点是程序运行速度快,空间占用小。

二、C++(基于11标准,配合boost库),不能用go时候的选择

选择C++有两个条件,基于C++11标准编写程序,并配合boost库。如果还是用C的思想在用C++,那还不如直接用C。使用C++,一定要将C++当成一个不同于C的全新语言使用,否则发挥不出C++的优势。

C++11相比于之前的C++是巨大的进步,并且gcc4.8.5的版本已经能够完整支持C++11了。C++11的特性包括自动类型推导,自动指针,lamba表达式等等。代码写起来更流畅,更精简了。唯一的缺点就是太复杂了,否则也就没go什么事了。

​ boost库为什么是一个必选项呢,因为boost库实在太强大了,嵌入式开发百分之九十以上的需求都可以通过boost库实现,完全不需要借助第三方库,包括串口操作boost库中都包含了。并且boost库大部分是头文件,交叉编译出来的so文件也并不大,占用不了太多空间。

​ https://www.boost.org/doc/libs/1_76_0/

看下boost的文档,你就知道boost库的功能有多强大。

C++11+boost库的缺点就是太复杂,学习起来比较困难,不过真要用熟了,绝对就成了C++大师了,跳槽升职加薪迎娶白富美走向人生巅峰不是梦!

下面列举几个C++ boost库的代码示例

用boost库解析命令行参数:

using namespace std; namespace bpo = boost::program_options; namespace blog = boost::log; namespace baio = boost::asio; // 解析命令行参数 int initFlag(int argc, char* argv[], string &configDir, string &logDir, int &logLevel) { //步骤一: 构造选项描述器和选项存储器 //选项描述器,其参数为该描述器的名字 bpo::options_description opts("all options"); //选项存储器,继承自map容器 bpo::variables_map vm; //步骤二: 为选项描述器增加选项 //其参数依次为: key, value的类型,该选项的描述 opts.add_options() ("configdir", bpo::value<string>()->default_value("./"), "set config file dir") ("logdir", bpo::value<string>()->default_value("./"), "set log file dir") ("loglevel", bpo::value<int>()->default_value(4), "set log level 0-6 panic fatal error warn info debug trace") ("help,h", "this is a log test program"); //步骤三: 先对命令行输入的参数做解析,而后将其存入选项存储器 //如果输入了未定义的选项,程序会抛出异常,所以对解析代码要用try-catch块包围 try { //parse_command_line()对输入的选项做解析 //store()将解析后的结果存入选项存储器 store(parse_command_line(argc, argv, opts), vm); } catch(...) { cout << "command line param is not correct" << endl; cout << opts << endl; return -1; } //步骤四: 参数解析完毕,处理实际信息 if(vm.empty()) //这里不会为空,因为设置了默认值 { } //count()检测该选项是否被输入 if(vm.count("help") ) {//若参数中有help选项 //options_description对象支持流输出, 会自动打印所有的选项信息 cout << opts << endl; return 1; } //variables_map(选项存储器)是std::map的派生类,可以像关联容器一样使用, //通过operator[]来取出其中的元素.但其内部的元素类型value_type是boost::any, //用来存储不确定类型的参数值,必须通过模板成员函数as<type>()做类型转换后, //才能获取其具体值. if(vm.count("configdir") ) { configDir = vm["configdir"].as<string>(); } if(vm.count("logdir") ) { logDir = vm["logdir"].as<string>(); } if(vm.count("loglevel") ) { logLevel = vm["loglevel"].as<int>(); } return 0; } 

讯享网

用boost库进行日志记录,同时记录至终端和文件中,并且文件支持自动分割,自动删除:

讯享网using namespace std; namespace bpo = boost::program_options; namespace blog = boost::log; namespace baio = boost::asio; // 初始化日志,日志级别0-6 panic fatal error warn info debug trace int initLog(string logPre, string logdir, int logLevel) { if ((logdir.length() > 0) && (*(--logdir.end()) == ':')) { logdir += "/"; } // 设置日志同时输出至文件和标准输出 auto console_sink = blog::add_console_log( std::cout, blog::keywords::format = (blog::expressions::stream << blog::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S.%f") << " - [" << blog::trivial::severity << "] : " << blog::expressions::smessage), blog::keywords::auto_flush = true ); auto file_sink = blog::add_file_log( blog::keywords::file_name = logPre + ".log", // blog::keywords::target_file_name = logPre + "_%Y%m%d_%3N.log", blog::keywords::enable_final_rotation = false, blog::keywords::rotation_size = 1 * 1024 * 1024, // blog::keywords::time_based_rotation = blog::sinks::file::rotation_at_time_point(0, 0, 0), blog::keywords::format = (blog::expressions::stream << blog::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S.%f") << " - [" << blog::trivial::severity << "] : " << blog::expressions::smessage), blog::keywords::auto_flush = true, blog::keywords::open_mode = ios_base::app ); file_sink->locked_backend()->set_file_collector(blog::sinks::file::make_collector( blog::keywords::target = logdir, //folder name. blog::keywords::max_size = 3 * 1024 * 1024 //The maximum amount of space of the folder. // blog::keywords::min_free_space = 100 * 1024 * 1024 //Reserved disk space minimum. )); file_sink->locked_backend()->scan_for_files(); // 设置日志输出级别 blog::trivial::severity_level logsevirity[]{ blog::trivial::fatal, blog::trivial::fatal, blog::trivial::error, blog::trivial::warning, blog::trivial::info, blog::trivial::debug, blog::trivial::trace}; // console_sink->set_filter(blog::trivial::severity >= logsevirity[LogLevel]); file_sink->set_filter(blog::trivial::severity >= logsevirity[logLevel]); // 只有文件过滤日志 blog::add_common_attributes(); return 0; } void logFunc(int Id) { BOOST_LOG_TRIVIAL(trace) << Id << "A trace severity message"; BOOST_LOG_TRIVIAL(debug) << Id << "A debug severity message"; BOOST_LOG_TRIVIAL(info) << Id << "An informational severity message"; BOOST_LOG_TRIVIAL(warning) << Id << "A warning severity message"; BOOST_LOG_TRIVIAL(error) << Id << "An error severity message"; BOOST_LOG_TRIVIAL(fatal) << Id << "A fatal severity message"; } 

用boost库进行串口读写

using namespace std; namespace bpo = boost::program_options; namespace blog = boost::log; namespace baio = boost::asio; void serialFunc(void) { try { baio::io_service io_context; baio::serial_port sp(io_context); sp.open("/dev/ttyS2"); //设置串口参数 sp.set_option(baio::serial_port::baud_rate(9600)); sp.set_option(baio::serial_port::flow_control()); sp.set_option(baio::serial_port::parity()); sp.set_option(baio::serial_port::stop_bits()); sp.set_option(baio::serial_port::character_size(8)); boost::system::error_code err; while(true) { boost::array<char, 128> buf; boost::system::error_code error; size_t len = sp.read_some(baio::buffer(buf), error); if(error) { throw boost::system::system_error(error); // Some other error. } BOOST_LOG_TRIVIAL(info) << "Serial recvd: " << buf.data(); sp.write_some(baio::buffer(buf), error); if(err) { throw boost::system::system_error(error); // Some other error. } } } catch(const std::exception& e) { BOOST_LOG_TRIVIAL(error) << "Serial error: " << e.what(); return; } } 

用boost库进行网络通信

讯享网using namespace std; namespace bpo = boost::program_options; namespace blog = boost::log; namespace baio = boost::asio; void tcpClientFunc(void) { try { baio::io_context io_context; baio::ip::tcp::tcp::resolver resolver(io_context); baio::ip::tcp::tcp::resolver::results_type endpoints = resolver.resolve("192.168.205.137", "60000"); baio::ip::tcp::tcp::socket socket(io_context); baio::connect(socket, endpoints); BOOST_LOG_TRIVIAL(info) << "Tcp Client connect ok."; for (;;) { boost::array<char, 128> buf; boost::system::error_code error; size_t len = socket.read_some(boost::asio::buffer(buf), error); if (error == boost::asio::error::eof) { BOOST_LOG_TRIVIAL(warning) << "Tcp Client connect closed."; break; // Connection closed cleanly by peer. } else if (error) { throw boost::system::system_error(error); // Some other error. } BOOST_LOG_TRIVIAL(info) << "Tcp Client recvd: " << buf.data(); // std::cout.write(buf.data(), len); } } catch(const std::exception& e) { BOOST_LOG_TRIVIAL(error) << "Tcp Client connect error: " << e.what(); return; } } void tcpServerChildFunc(baio::ip::tcp::tcp::socket sT) { time_t now = time(0); string times = ctime(&now); for(;;) { boost::system::error_code ignored_error; baio::write(sT, baio::buffer(times), ignored_error); if (ignored_error == boost::asio::error::eof) { BOOST_LOG_TRIVIAL(warning) << "Tcp Server connect closed."; return; } else if (ignored_error) { BOOST_LOG_TRIVIAL(error) << "Tcp Server connect error: " << boost::system::system_error(ignored_error).what(); return; } this_thread::sleep_for(chrono::seconds(5)); } } void tcpServerFunc(void) { baio::io_context io_context; baio::ip::tcp::tcp::acceptor acceptor(io_context, baio::ip::tcp::tcp::endpoint(baio::ip::tcp::tcp::v4(), 60000)); for (;;) { try { baio::ip::tcp::tcp::socket socket(io_context); acceptor.accept(socket); auto t = thread(tcpServerChildFunc, move(socket)); t.detach(); } catch (std::exception &e) { BOOST_LOG_TRIVIAL(error) << "Tcp Server accept error: " << e.what(); } } } 
小讯
上一篇 2025-02-28 07:46
下一篇 2025-02-25 09:36

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/44763.html