精华内容
下载资源
问答
  • C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例C++编程实例...
  • C++编程实例100篇

    千次下载 热门讨论 2013-08-28 10:48:45
    C++编程实例100篇,里面有很多很基础的编程实例,可以作为参考。
  • C++编程实例详解C++编程实例详解C++编程实例详解C++编程实例详解C++编程实例详解C++编程实例详解C++编程实例详解C++编程实例详解C++编程实例详解C++编程实例详解C++编程实例详解C++编程实例详解C++编程实例详解C++...
  • c++编程实例

    万次阅读 多人点赞 2018-05-30 10:03:55
    } // auto 类型也是 C++11 新标准中的,用来自动获取变量的类型 for (auto &x : my_array) { x *= 2; cout ; } 结果: /tmp/381229462/main.cpp:29:1: error: expected unqualified-id for (int &x : my_array) ^ ...
    1、
    #include<iostream>
    using namespace std;
    int main()
    {
    	cout << "Hello world!" << "\n";
    	return 0;
    }

    结果

    Hello world!
    
    2、
    #include<iostream>
    #include<string>
    using namespace std;
    
    extern int a, b;
    extern int c;
    extern float f;
    int main()
    {
    	//定义变量
    	int a, b;
    	int c;
    	float f;
    	
    	//实际初始化
    	a = 10;
    	b = 20;
    	c=a+b;
    	
    	cout << c << endl;
    	f = 70.0/3.0;
    	cout << f << endl;
    	return 0;
    }
    

    结果:

    30
    23.3333
    
    

    3、

    #include<iostream>
    using namespace std;
    #define LENGTH 10
    #define WIDTH 5
    //#define NEWLINE '\n'
    
    int main()
    {
    	int area;
    	area = LENGTH * WIDTH;
    	cout << area;
    //	cout << NEWLINE;
    	return 0;
    }

    结果:

    50

    3、常量定义demo2

    int main()
    {
    	const int LENGTH = 10;
    	const int WIDTH = 5;
    	int area;
    	area = LENGTH * WIDTH;
    	cout << area;
    //	cout << NEWLINE;
    	return 0;
    }
    

    结果:

    50

    4、static存储类用法

    void func(void);
    static int count = 10;
    int main()
    {
    	while(count--)
    	{
    		func();
    	}
    	return 0;
    }
    void func(void)
    {
    	static int i = 5;
    	i++;
    	std::cout << "变量i为" << i;
    	std::cout << ",变量count为" << count << std::endl;
    }
    

    结果:

    变量i为6,变量count为9
    变量i为7,变量count为8
    变量i为8,变量count为7
    变量i为9,变量count为6
    变量i为10,变量count为5
    变量i为11,变量count为4
    变量i为12,变量count为3
    变量i为13,变量count为2
    变量i为14,变量count为1
    变量i为15,变量count为0
    
    static int i = 5;

    改为

    int i = 5;

    结果:

    变量i为6,变量count为9
    变量i为6,变量count为8
    变量i为6,变量count为7
    变量i为6,变量count为6
    变量i为6,变量count为5
    变量i为6,变量count为4
    变量i为6,变量count为3
    变量i为6,变量count为2
    变量i为6,变量count为1
    变量i为6,变量count为0

    4、extern存储类

    main.cpp

    #include <iostream>
    
    int count;
    extern void write_extern();
    
    int main()
    {
    count = 5;
    write_extern();
    }

    support.cpp

    #include <iostream>
    
    extern int count;
    
    void write_extern(void)
    {
    std::cout << "Count is" << count << std::endl;
    }

    运行:

    $ g++ main.cpp support.cpp -0 write
    $ ./write
    结果:
    Count is 5

    5、循环

    while语句

    int main()
    {
    	int a = 10;
    	while( a < 20 )
    	{
    		cout << a << endl;
    		a++;
    	}
    }

    结果:

    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    for语句(基于范围的)

    int my_array[5] = {1, 2, 3, 4, 5}; // 每个数组元素乘于 2 
    for (int &x : my_array) 
    { 
    	x *= 2; 
    	cout << x << endl; 
    } // auto 类型也是 C++11 新标准中的,用来自动获取变量的类型 for (auto &x : my_array) { x *= 2; cout << x << endl; }
    

    结果:

    /tmp/381229462/main.cpp:29:1: error: expected unqualified-id
    for (int &x : my_array) 
    ^
    1 error generated.
    
    exit status 1

    原因:

    程序运行是从main函数入口执行的,把程序语句放在全局空间里不被执行。要放在某个函数里或宏里等等


    rang for 遍历字符串,将小写变成大写

    #include <iostream>
    #include <cctype>
    #include <string>
    using namespace std;
    //string str("guo zehui");
    string str = "guozehui";
    int main()
    {
    	for (auto &c : str)
    	{
    		c = toupper(c);
    		
    	}
    	cout << str << endl;
    }

    结果:

    GUOZEHUI

    #include <cctype>的函数

    6、生成随机数

    #include <iostream>
    #include <cmath>
    #include <cstdlib>
    using namespace std;
    
    int main()
    {
    	int i,j;
    	srand( (unsigned)time( NULL ));
    	for (i = 0; i < 10; i++)
    	{
    		j=rand();
    		cout << j << endl;
    	}
    }
    

    结果:

    1338961599
    1566172925
    1291431620
    1754761110
    805075681
    329934179
    1769264811
    1209019267
    1283590728
    579234732

    先调用srand()函数,再使用rand()返回随机数。

    7、class类的定义

    #include <iostream>
    using namespace std;
    
    
    class Box
    {
    	public:
    	double length;
    	double breadth;
    	double heigth;
    };
    int main()
    {
    	Box box1;
    	Box box2;
    	double volume = 0.5;
    	box1.length = 1;
    	box1.breadth = 2;
    	box1.heigth = 3;
    	
    	box2.length = 4;
    	box2.breadth = 5;
    	box2.heigth = 6;
    	
    	volume = box1.length*box1.breadth*box1.heigth;
    	cout << volume << endl;
    }

    结果:

    6

    class定义成员函数

    #include <iostream>
    using namespace std;
    
    
    class Box
    {
    	public:
    	double length;
    	double breadth;
    	double heigth;
    	
    	double getVolume(void)
    	{
    		return length*breadth*heigth;
    	}
    	void setLength(double len)
    	{
    		length = len;
    	}
    	void setBreadth(double bre)
    	{
    		breadth = bre;
    	}
    	void setHeigth(double hei)
    	{
    		heigth = hei;
    	}
    };
    int main()
    {
    	Box box1;
    	Box box2;
    	double volume = 0.5;
    	box1.setLength(1.0);
    	box1.setBreadth(2.0);
    	box1.setHeigth(3.0);
    	
    	volume = box1.getVolume();
    	
    	cout << volume << endl;
    }

    结果:

    6


    疑点:

    1、explicit构造函数

    2、string str ("guozehui");跟string str = "guozehui";区别

    C++中的string str问题.

    string是个类,string str,是定义一个名叫str的字符串对象。
    
    str内部保存着字符串的内容,通过str.c_str()可以获取这个字符串的首地址。
    string str = "ABC",这也不是将str赋值为"ABC"的首地址,而是使用"ABC"为值来初始化一个string类
    在字符串变量中存放的是字符串的指针(即字符串的地址)。在vc++6.0环境下,string变量在内存中占4个字节,指针变量在内存中也是占4个字节,它们都用于存放变量的首地址。

    字符串的首地址不是字符串的第一个字符!字符串的首地址是字符串的第一个字符的地址,这第一个字符的地址的内容才是这个字符串的第一个字符。

    4、函数定义中return_type,当无返回值时,用void

    5、main函数的参数

    包含一个整型和一个指针数组

    形式:

    int main(int argc, char* argv[])

    6、&x,引用调用,将引用的地址复制给形式参数,修改形参会影响实际参数。

    7、ctime

    #include <ctime> 包含有什么函数??

    定义time_t型t变量

    time_t t;

    7、定义静态常量

    C++中如何在类中定义静态const的string?

    只有静态整数(注意,不仅仅是整型)常量可以在类中声明并初始化,其他的都必须在类外初始化。
    8、

    关于C++的class中的public,protected,private;

    要给“别人”使用的变量和函数就用public
    只给自己使用的变量和函数就用private
    protected。。。这个只能说概念了。。。就是想要允许他的子类直接访问,就用protected

    8、类::成员(参数)

    eg:Box::get(double len);

    9、#include <>与#include ""区别

    include <>引用的是编译器的类库路径里面的头文件。

    #include ""引用的是程序目录的相对路径中的头文件。

    #include< > 和 #include” ” 的区别

    10、.hpp(Header Plus Plus)c++程序头文件格式

    .hpp与.h区别

    展开全文
  • UHD C/C++ 编程实例 USRP发送、接收数据

    万次阅读 多人点赞 2016-11-12 20:41:40
    UHD C/C++ 编程实例 USRP发送、接收数据 UHD库函数简介:发送函数、接收函数 C/C++ USRP 发送数据、USRP 接收数据 g++ 链接UHD库

    UHD C/C++ 编程实例 USRP发送、接收数据

    如有相关问题,欢迎随时讨论交流 jxwxg@foxmail.com

    1. UHD库函数简介

    1.1 发送函数

    新建一个usrp设备
    std::string args = " "; args指定USRP地址,配置USRP参数等
    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);

    设置时钟源和时钟频率
    std::string ref = "internal"; // internal, external, MIMO.
    usrp->set_clock_source(ref);
    double rate = 40e6;
    usrp->set_master_clock_rate(rate);

    usrp->get_clock_source() //获取当前的时钟源
    usrp->get_clock_sources() //获取所有可用的时钟源
    usrp->get_master_clock_rate(); //获取时钟频率

    设置采样率
    double samp_rate = 20e6;
    usrp->set_tx_rate(samp_rate);

    usrp->get_tx_rate() //获取当前的采样率
    usrp->get_tx_rates() //获取采样率的采样范围

    设置发射中心频点
    double freq = 2.412e9;
    usrp->set_tx_freq(freq);

    usrp->get_fe_tx_freq_range();
    usrp->get_tx_freq();
    usrp->get_tx__freq_range();

    设置发射增益
    double tx_gain = 60;
    usrp->set_tx_gain(tx_gain);

    设置发射天线
    默认情况下无需设置发射天线,如需指定特定发射天线时设置。
    usrp->set_tx_antenna(0);
    usrp->get_tx_antenna();
    usrp->get_tx_antennas();

    创建发送流
    新建发送流参数
    std::string cpu_format = "fc32";
    目前cpu_format支持的类型有:fc64 - complex fc32 - complex sc16 - complex sc8 - complex
    std::string wire_format = "sc16";
    目前wire_format支持的类型有:sc16 - Q16 I16 sc8 - Q8_1 I8_1 Q8_0 I8_0

    uhd::stream_args_t stream_args(cpu_format, wire_format);
    uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);

    中频数据管理
    uhd::tx_metada_t md; //结构体描述接收到的中频信号
    md.start_of_burst = false; // 设置为真的时候发送第一个数据包
    md.end_of_burst = false; // 设置为真的时候发送最后一个数据包
    md.has_time_spec = false; // 设置为false时立即发送,设置为真的时候在特定时间发送

    1.2 接收函数

    创建一个usrp
    std::string args = " ";
    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);

    设置时钟源和时钟频率
    std::string ref = "internal"; //internal, external and MIMO
    usrp->set_clock_source(ref);

    double clock_rate = 40e6;
    usrp->set_master_clock_rate(clock_rate);

    设置采样率
    double rate = 20e6;
    usrp->set_rx_rate(rate);

    设置中心频率
    double freq = 2.412e9;
    usrp->set_rx_freq(freq);

    设置增益
    double rx_gain = 50;
    usrp->set_rx_gain(rx_gain);

    创建接收流
    std::string cpu_format = "fc32";
    std::string wire_format = "sc16";
    uhd::stream_args_t stream_args(cpu_format, wire_format);
    uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);

    设置接收模式
    uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);

    //UHD_STREAM_MODE_START_CONTINUOUS=97, //UHD_STREAM_MODE_STOP_CONTINUOUS=111, //UHD_STREAM_MODE_NUM_SAMPS_AND_DONE=100, //UHD_STREAM_MODE_NUM_SAMPS_AND_MORE=109

    stream_cmd.num_samps = 1000; // 接收采样点数
    stream_cmd.stream_now = true; //现在开始接收
    rx_stream->issue_stream_cmd(stream_cmd); //配置rx_stream参数

    2. USRP发送数据

      代码实现USRP发送二进制文件802.11a_BUPT41.seg内的数据。里面的数据为float complex类型,复数的实部和虚部交替存储。即如下图所示。用户可以把要发送的数据生成对应的二进制文件,也可以直接写成数组放在代码中。注意:float类型数据的单位1就是 “1”。
    这里写图片描述

    源码

    #include <uhd/usrp/multi_usrp.hpp>
    #include <signal.h>
    
    #define SAMPLE_PER_BUFF 2000
    
    int stop_signal_called = 0;
    void sig_int_handle(int)
    {
        stop_signal_called = 1;
        printf("stop tx.........\n");
        exit(0);
    }
    
    int main()
    {
        std::string addr_args = " ";
        uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(addr_args);
        printf("Create a usrp......\n");
    
        // set the ref and clock rate
        std::string ref = "internal";
        usrp->set_clock_source(ref);
    
        float clock_rate = 40e6;
        usrp->set_master_clock_rate(clock_rate);
        printf("set the  clock rate %0.2f \n", usrp->get_master_clock_rate() );
    
        // set the sample rate
        float samp_rate = 20e6;
        usrp->set_tx_rate(samp_rate);
        printf("set the tx sample rate to %0.2f \n", usrp->get_tx_rate());
    
        // set the center frequency
        float center_freq = 2.412e9;
        usrp->set_tx_freq(center_freq);
        printf("set the tx center freq to %0.2f \n", usrp->get_tx_freq());
    
        // set the rf gain
        float tx_gain = 90;
        usrp->set_tx_gain(tx_gain);
        printf("set the tx gain to %0.2f \n", usrp->get_tx_gain());
    
    
        // create a tx stream
        std::string cpu_format = "fc32";
        std::string wire_format = "sc16";
        uhd::stream_args_t stream_args(cpu_format, wire_format);
        uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
    
        uhd::tx_metadata_t md;
    
        // catch the INT signal
        signal(SIGINT, sig_int_handle);
        float read_buff[SAMPLE_PER_BUFF * 2] = {0};
    
        while(!stop_signal_called)
        {
            FILE *fp = fopen("802.11a_BUPT41.seg", "rb");
            md.start_of_burst = false;
            md.end_of_burst = false;
    
    
            while( (!md.end_of_burst) && (!stop_signal_called) )
            {
                int read_length = 0;
                if( (read_length = fread(read_buff, sizeof(uint32_t), SAMPLE_PER_BUFF * 2, fp) ) == (SAMPLE_PER_BUFF * 2) )
                {
                    //int index;
                    //for(index = 0; index < SAMPLE_PER_BUFF * 2; index++)
                    //    printf("%0.2f ", read_buff[index]);
                    //puts("");
    
                    //md.start_of_burst = true;
                    tx_stream->send(read_buff, SAMPLE_PER_BUFF, md);
                    //md.start_of_burst = false;
                    //sleep(1);
                }
                else if(read_length >= 0)
                {
                    md.end_of_burst = true;
                }
            }
    
            fclose(fp);
        }
    
    
        return 0;
    }
    

    编译
    g++ 编译时需要链接uhd库,系统需提前安装UHD驱动。具体过程参见之前博客。Ubuntu14.04 源码安装 UHD3.8.0
    g++ tx.cpp -o tx -luhd

    3. USRP接收数据

      启动USRP,并使USRP一直接收数据。

    源码

    #include <uhd/usrp/multi_usrp.hpp>
    #include <csignal>
    
    #define SAMPLE_PER_BUFF 2000
    
    int stop_signal_called = false;
    void sig_int_handle()
    {
        stop_signal_called = true;
    }
    
    int main()
    {
        std::string addr_args = " ";
        uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(addr_args);
    
        // set the clock source and clock rate
        std::string ref = "internal";
        usrp->set_clock_source(ref);
    
        float clock_rate = 40e6;
        usrp->set_master_clock_rate(clock_rate);
        printf("set the  clock rate %0.2f \n", usrp->get_master_clock_rate() );
    
        // set the sample rate
        float samp_rate = 20e6;
        usrp->set_rx_rate(samp_rate);
        printf("set the tx sample rate to %0.2f \n", usrp->get_rx_rate());
    
        // set the center frequency
        float center_freq = 2.412e9;
        usrp->set_rx_freq(center_freq);
        printf("set the tx center freq to %0.2f \n", usrp->get_rx_freq());
    
        // set the rf gain
        float rx_gain = 80;
        usrp->set_rx_gain(rx_gain);
        printf("set the tx gain to %0.2f \n", usrp->get_rx_gain());
    
        std::string cpu_format = "fc32";
        std::string wire_format = "sc16";
        uhd::stream_args_t stream_args(cpu_format, wire_format);
        uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
    
        uhd::rx_metadata_t md;
    
        //uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
        uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
        stream_cmd.num_samps = SAMPLE_PER_BUFF;
        stream_cmd.stream_now = true;
        //stream_cmd.time_spec = uhd::time_spec_t();
        stream_cmd.time_spec = usrp->get_time_now();
        rx_stream->issue_stream_cmd(stream_cmd);
    
        uint32_t buff[SAMPLE_PER_BUFF*2] = {0};
        unsigned long long num_total_samps = 0;
    
        while(!stop_signal_called)
        {
            //int num_rx_samps = rx_stream->recv(buff, SAMPLE_PER_BUFF, md);
            memset(buff, 0, SAMPLE_PER_BUFF * sizeof(uint32_t));
            int num_rx_samps = rx_stream->recv(buff, SAMPLE_PER_BUFF, md, 3.0, false);
            if(md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT)
            {
                printf("Timeout while streaming......\n");
                break;
            }
            if(md.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW)
            {
                printf("Overflowing while stream......\n");
                continue;
            }
            if(md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE)
            {
                //printf("Receive error: %s \n", md.strerror());
                continue;
            }
    
        //printf("num_rx_samps = %d \n",num_rx_samps);
            num_total_samps += num_rx_samps;
    
        }
        printf("num_total_samps = %d \n", num_total_samps);
    
        stream_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS;
        rx_stream->issue_stream_cmd(stream_cmd);
    
        return 0;
    }

    编译
    g++ 编译时需要链接uhd库,系统需提前安装UHD驱动。具体过程参见之前博客。Ubuntu14.04 源码安装 UHD3.8.0
    g++ rx.cpp -o rx -luhd

    4. 结论

      以上代码在Ubuntu上采用USRP B200测试通过。
      掌握UHD库函数的使用、g++ 链接 UHD库等是基于USRP开发软件无线电项目的基础。之后,我们可以进一步设计发送程序和接收程序,用USRP搭建一套SDR 收发系统。

    展开全文
  • [C++]C++编程实例

    千次阅读 2016-11-26 22:25:19
    实例1 设某次体育比赛的结果有4中可能:胜(WIN)、负(LOSE)、平局(TIE)、比赛取消(CANCEL),编写程序顺序输出这4中情况。 知识点:主要是练习枚举类型enum的使用

    实例1

       设某次体育比赛的结果有4中可能:胜(WIN)、负(LOSE)、平局(TIE)、比赛取消(CANCEL),编写程序顺序输出这4中情况。

       知识点:主要是练习枚举类型enum的使用

      

    编译运行结果

       

    实例2

        将两个整数交换次序后输出。

       知识点:值传递是指当发生函数调用时,给形参来分配内存空间,并用实参来初始化形参(直接将实参的值传递给形参)。这一过程是参数值的单向传递关系,一旦形参获得了值便与实参脱离关系,此后无论形参发生了什么样的改变,都不会影响到实参。

       

      编译运行结果

      

      分析:从上面的运行结果可以看出,并没有达到交换的目的。这是因为,采用的是值传递,函数调用时传递的是实参的值,是单向传递过程。形参值的改变对实参值不起作用。

    实例3

       利用引用传递完成实例2功能

       知识点:① 声明一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象。② 一旦一个引用被初始化后,就不能改为指向其他对象。③ 用引用作为形参,在函数调用时发生的参数传递,称为引用传递。

      

      编译运行结果

      

      可见,通过引用传递实现了数据交换的功能。

    实例4

      值传递与引用传递的比较。

      分析:子函数 fiddle 的第一个参数 in1 是普通的 int型,被调用时传递的是实参v1的值,第二个参数in2是引用,被调用时由实参v2初始化后称为v2的一个别名。于是在子函数中对参数 in1 的改变不影响实参,而对形参in2的改变实质上就是对主函数中变量 v2的改变。因而返回主函数后,v1值没有变化,v2值发生了变化。

           

    编译运行结果

       

    展开全文
  • 众所周知,KEIL / MDK是支持C++编程方式的。但是就目前来说,使用C++开发嵌入式的程序员还是比较少,就我个人认为原因是一方面KEIL / MDK对C++程序的支持还不够全面,另一方面则是C++程序的体量相较于C程序过于庞大...

    众所周知,KEIL / MDK是支持C++编程方式的。但是就目前来说,使用C++开发嵌入式的程序员还是比较少,就我个人认为原因是一方面KEIL / MDK对C++程序的支持还不够全面,另一方面则是C++程序的体量相较于C程序过于庞大,对于小型的应用来说没有必要,而且嵌入式开发程序员通常C++功底并不高,C才是他们的拿手好戏。但我认为随着MCU性能的逐渐提升,嵌入式C++的开发潜力将会越来越多的被发掘。并且C++的标准还在更新,总体来说C++的活力是高于C的。当然,最重要的一点则是C++兼容了C,有人甚至说只要C不死,C++就不会死!我认为这是很有道理的。

    作为一个嵌入式和智能终端都有一点接触的程序员来说,我当然是更希望我的代码能够更容易地移植。那么使用C++编程的方式无疑就要合理一些。最近两天刚刚忙完期末测评,突然兴起就写了这篇博文,那么接下来我就以自己在KEIL / MDK上建的一个STM32F1的C++模板工程为例,聊一聊C++编程的相关事项,如果有错误或者不足请各位勿怪,也欢迎各位留言和我交流。

    准备C++模板工程:

    首先我们要新建一个KEIL / MDK工程,如果没建过的话就花点时间百度教程吧,如果不想多费力气那也OK,直接把一个C工程的main.c替换为main.cpp即可。工程的配置均保持原样无需改变。但此时编译的这个工程应该会出一些错误,当文件后缀是C的时候IDE会使用C编译器进行编译,如果文件后缀是CPP则IDE使用C++编译器进行编译,工程包含的头文件是使用C++编译器进行编译的,不过头文件声明的还是C文件的符号,所以IDE会无法正确编译链接。此时我们应该将头文件所有声明C符号的部分用预编译宏加extern "C" { }的形式包含起来,告诉编译器该段要使用C编译器进行编译。具体形式如下:

    #ifdef __cplusplus
     extern "C" {
    #endif
    
    ... your C declared part ...
    
    #ifdef __cplusplus
    	}
    #endif

    当使用STM32标准库编写程序的时候会发现它所有的头文件都是这样处理过的。也就是说库函数完全兼容C++。这也是我们开发C++程序的强大后盾。在准备了基本工程后就可以在main.cpp文件中使用C++编程了,但还应该注意的是,C编译器不能直接引进CPP文件的符号,同理C++编译器也不能直接引进C文件的符号。当C文件要extern 一个CPP文件的符号时,这个CPP文件的符号定义应该用extern "C" { }进行修饰,否则不能通过编译链接。同样地,当CPP文件要引进一个C文件的符号时也要在CPP文件中使用extern "C" { }进行修饰。另外汇编启动文件的[WEAK]声明仅对C文件符号有效,所以我们编写外设中断服务方法时应该写在C文件中,或者在CPP文件中使用exetrn "C" { }修饰符。

    建立的C++模板工程文件目录如下:

    其中serial.c和retarget.c都是在KEIL / MDK的安装目录下复制过来的,这两个文件提供了对C标准库和C++标准库的部分支持。添加上述文件到工程后我们就能正常使用C++的std标准库进行编程了。关于serial.c和retarget.c我们需要知道以下一些知识:

    KEIL / MDK在semihosting模式下,标准库的输入输出流并没有定向到串口,要正常使用std标准库就需要先关闭semihosting模式,即使用预编译指令如下:

    #pragma import(__use_no_semihosting_swi)

    关闭semihosting后需要对部分标准库方法进行重定向编写,既将输入输出流重定向至STM32的串口端。而retarget.c里面就实现了相关的方法。

    在serial.c中定义了对串口的初始化以及发送和接收的方法。为了让串口能在运行系统入口方法前被初始化而不是在用户main.c中初始化,文件定义了如下方法进行对串口的提前初始化。

    /*----------------------------------------------------------------------------
      Superclass to initialize the serial interface
     *----------------------------------------------------------------------------*/
    /* 引进原始__rt_entry方法 */
    extern void $Super$$__rt_entry(void);
    
    /* 定义新__rt_entry方法 */
    void $Sub$$__rt_entry(void)  {
      SER_Init();
    /* 调用原始__rt_entry方法; */
      $Super$$__rt_entry();
    }

    通过$super$$和$sub$$两个编译器指令的结合使用,将串口初始化方法“填”进了系统的入口方法中。其中SER_Init()方法初始化了USART1。我们也无需再在main.c中初始化串口。另外标准库需要用户提供堆内存进行支持。STM32的启动文件中已经定义了用户堆。所以我们无需再定义,但默认的堆容量对于标准库来说还是太过于小,要手动修改堆的尺寸如下:

    Heap_Size       EQU     0x00001000	; Extend for using C++ std lib

    还有需要注意的是,KEIL / MDK 的C++编译器默认失能异常捕获机制,如果你的代码中用到了该机制,那么就需要在工程配置的"Options for Target - C/C++ - Misc controls"选项中添加'--exceptions'选项。添加如下图所示:

    C++模板工程测试:

    弄完上面的这些步骤之后,这个模板工程就可以随心所欲地进行C++程序编写了,下面我们编写一点简单代码进行测试标准库,代码如下:

    #include <string>
    #include <iostream>
    #include "ledx.h"
    #include "tick.h"
    
    
    int main(void) {
    	
    	LED_Init();		// 初始化LED
    	Tick_Init();		// 初始化SYSTICK
    	
    	std::string str("the float number is ");
    	float number = 0;
    	
    	while (1) {
    		std::cout << str << number++ << std::endl;
    		
    		led1_on();
    		led2_on();
    		delay_ms(500);
    		led1_off();
    		led2_off();
    		delay_ms(500);
    	}
    }

    烧录运行并输出到PC串口助手的内容如下:

    可以看到运行结果是正确的。但实际情况却是几乎没人愿意这么用在嵌入式开发中,原因也很简单。

    这是上面那段测试程序编译链接后的输出窗口,勤俭持家的嵌入式程序员看到这个估计要炸锅了吧!这点代码用纯C写最多占6KB FLASH和极少的RAM资源,但引入C++标准库后居然要占用52KB FLASH和27KB RAM,这不太科学啊!可能习惯编写终端的高富帅程序员看了会不以为然:这么点都不舍得花,怎么能过上有品质的生活啊!但我们的嵌入式程序员却表示:有钱也不能这样花啊,我们的每一分钱都要花得值当,再说我们的积蓄哪里有这么多!(这才是原因,哈哈尴尬!)

    优化C++程序:

    当然以上只是玩笑话,不过作为一个优秀的嵌入式开发程序员,代码优化永远都是重中之重。那么我们为了勤俭节约一把,自然是不能滥用标准库的,不过得益于C++的优越性,我们可以轻松地编写自己的功能类用于处理一般性的问题,就拿以上测试程序为例,不就是需要一个类似cout输出形式的类嘛!这还不容易!然后我们就开始简单地编写一个类用于实现上述功能。

    下面是这个类的头文件部分:

    #include "stdio.h"
    #include "stdarg.h"
    #include "string.h"
    
    // NAME SPACE OUT DEFINE
    namespace cchar {
    	
    	// CONST TYPE VARIABLE
    	const char tint = 'd';
    	const char tuint = 'u';
    	const char tchar = 'c';
    	const char tftp = 'f';
    	
    	// CONST ENTER VARIABLE 
    	const char endl = '\n';
    }
    using namespace cchar;
    
    // STRING OUTPUT CLASS
    class ostring {
    public:
    	ostring& operator << (const char* str);
    	ostring& operator << (int num);
    	ostring& operator << (unsigned int num);
    	ostring& operator << (short num);
    	ostring& operator << (unsigned short num);
    	ostring& operator << (char num);
    	ostring& operator << (unsigned char num);
    	ostring& operator << (float num);
    	ostring& operator << (double num);
    private:
    	void put_string(const char* str, unsigned int cnt);
    	void put_number(char type, ...);
    };

    我们声明了一个ostring类,类里面啥数据成员都木有,只重载不同数据类型的运算符"<<"即可,私有的两个成员函数负责整合字符串并向串口发送。

    下面是ostring类的实现文件:

    #include "ostr.hpp"
    
    
    extern "C" { extern int put_char(int c);}
    // OUT STRING CLASS BASE PRINT FUNCTION
    void ostring::put_string(const char* str, unsigned int cnt) {
    	for (unsigned int index = 0; index < cnt; index++) {
    		put_char(str[index]);
    	}
    }
    
    // STRING OUTPUT CLASS PUT NUMBER FUNCTION
    void ostring::put_number(char type, ...) {
    	va_list arg;
    	char temp[20];
    	unsigned char cnt = 0;
    	
    	va_start(arg, type);
    	switch (type) {
    		case tint:
    			cnt = sprintf(temp, "%d", va_arg(arg, int));
    			break;
    		case tuint:
    			cnt = sprintf(temp, "%d", va_arg(arg, unsigned int));
    			break;
    		case tchar:
    			cnt = sprintf(temp, "%c", va_arg(arg, int));
    			break;
    		case tftp:
    			cnt = sprintf(temp, "%f", va_arg(arg, double));
    			break;
    	}
    	va_end(arg);
    	put_string(temp, cnt);
    }
    
    // STRING OUTPUT CLASS OPERATOR FUNCTION
    ostring& ostring::operator << (const char* str) {
    	put_string(str, strlen(str));
    	return *this;
    }
    ostring& ostring::operator << (int num) {
    	put_number(tint, num);
    	return *this;
    }
    ostring& ostring::operator << (unsigned int num) {
    	put_number(tuint, num);
    	return *this;
    }
    ostring& ostring::operator << (short num) {
    	put_number(tint, num);
    	return *this;
    }
    ostring& ostring::operator << (unsigned short num) {
    	put_number(tuint, num);
    	return *this;
    }
    ostring& ostring::operator << (char num) {
    	put_number(tchar, num);
    	return *this;
    }
    ostring& ostring::operator << (unsigned char num) {
    	put_number(tuint, num);
    	return *this;
    }
    ostring& ostring::operator << (float num) {
    	put_number(tftp, num);
    	return *this;
    }
    ostring& ostring::operator << (double num) {
    	put_number(tftp, num);
    	return *this;
    }

    这个CPP文件引进了发送单个字符到串口的方法put_char,put_string方法简单地将一个字符串依次发送出去,而put_number方法则是使用C标准库的可变参数对数据类型进行分类,再整合到字符串中再依次发出。这里为了节约开销,我没有用模板函数(试过的,开销显然比这个大)。把这两个文件添加进工程后再运行刚刚的测试程序,

    首先将测试程序修改成如下:

    #include "ledx.h"
    #include "tick.h"
    #include "ostr.hpp"
    
    
    int main(void) {
    	
    	LED_Init();		// 初始化LED
    	Tick_Init();		// 初始化SYSTICK
    
    	ostring cout;
    	float number = 0;
    	
    	while (1) {
    		cout << "the float number is " << number++ << endl;
    		
    		led1_on();
    		led2_on();
    		delay_ms(500);
    		led1_off();
    		led2_off();
    		delay_ms(500);
    	}
    }

    哈哈!现在我们也能像标准库那样输出了!再来看看这个程序的开销如何

    可以看出来吧?仅仅用了7KB不到的FLASH和6KB RAM资源,而且我们还没有将划分给标准库的那部分RAM回收,所以RAM实际上消耗是很小的。最后运行一下这个程序,其输出到串口助手的截图如下:

    结果依然是正确的,和标准输出唯一不同的是我没有控制输出精度。

    C++模板工程对操作系统的支持:

    在写这篇博文之前我也验证了在C++模板工程上运行RTOS的可行性。结果当然是可行的,而且不会出现任何问题。这正是得益于C++对C的兼容性。也就是说,C++具备在嵌入式开发的一切条件,真的是只欠东风(程序员)!另外,我还在C++模板工程上成功运行了自己这学期用C写的一个RTOS。我把它叫做REGINA,在上一篇博文里简短地介绍了一下,有兴趣的朋友不妨去下载下来使用看看,它是一个免费的自由软件,而它的体量已经被我精简地非常不错了。博文地址是http://blog.csdn.net/hlld__/article/details/78865260。不过如果有兴趣的你看到那篇博文后可能会感觉很奇怪,原谅我是用较官方性的语言来写的,这样能营造一些正式的气氛!哈哈!

    通过这个简单的实例,我们还模仿了用于标准输出的类,并实现了相关的功能。在实际嵌入式开发中为了节约体量还会干很多这样的事情,但就像我前面说的那样,C++给予了程序员这样的便利,仅仅很小的工作量就能实现我们想要的功能。而且相较与C程序而言,C++程序的可移植性、代码的可扩展性显然更高。更为重要的是C++处理大批次数据的能力及实现复杂逻辑的困难程度都要优于C程序,我相信随着MCU的运算能力不断增强,使用C++开发的程序员将会越来越多,而嵌入式C++的开发潜力也将更多地体现出来。

    展开全文
  • Redis C++编程实例

    千次阅读 2015-02-04 18:39:39
    基本功能步骤: 1,下载安装redis,下载地址:http://www.redis.cn/download.html。 2,下载安装hiredis,下载地址... 将libhiredis.so放到/usr/lib/目录下。 ...3,在hiredis-master目录下编写客户端程序。...#include "h
  • C++是面向对象的程序语言,区别我们的C语言,具体编程首先要定义一个类,类中包含私有成员以及公有成员两部分,私有成员主要是变量,公有成员主要是方法,另外还需要另外的.cpp程序来实现这些公有方法,以及一个...
  • C++编程实例-分支结构

    千次阅读 2009-12-16 17:37:00
    实验1 分支结构【实验目的】通过本实验,了解C语言的分支结构程序设计的方法及语法规则的正确使用。【实验内容】利用随机函数出个位数加/减法算术题#include#include#includeusing namespace std;...
  •  很少有专题讲内核中的C++编程,中文资料恐怕更是罕见。由于C++的普及性、与C的亲密关系,以及大部分情况下程序员都使用C++编译器编译C程序的事实,当初学者听说内核中“不容易”(笔者也听说过“无法”二字)...
  • C++编程实例-for循环结构

    千次阅读 2009-12-16 17:41:00
    实验3 for循环结构【实验目的】通过本实验,掌握循环结构程序设计的编程方法,掌握循环方面的编程技巧。【实验要求】⑴学会使用for语句;⑵掌握循环结构程序设计方法;【实验内容】将所有三位数中的对称数以5个一行...
  • C++编程实例-while循环结构

    千次阅读 2009-12-16 17:39:00
    实验2 while循环结构【实验目的】通过本实验,掌握循环结构程序设计的编程方法,掌握循环方面的编程技巧。【实验要求】⑴学会使用while语句;⑵掌握循环结构程序设计方法;【实验内容】以下程序任选两个从键盘上...
  • C++编程实例-多重循环结构

    千次阅读 2009-12-16 17:43:00
    实验4 多重循环结构【实验目的】通过本实验,掌握循环结构嵌套的程序设计编程方法。【实验要求】掌握循环结构嵌套的程序设计方法;【实验内容】输出2-100之间的所有素数。#includeusing namespace std;int main...
  • Visual C++MFC编程实例 教程Visual C++MFC编程实例 教程Visual C++MFC编程实例 教程Visual C++MFC编程实例 教程Visual C++MFC编程实例 教程Visual C++MFC编程实例 教程Visual C++MFC编程实例 教程Visual C++MFC编程...
  • Visual C++ MFC编程实例

    热门讨论 2007-09-29 21:07:30
    Visual C++ MFC编程实例
  • 本代码是c++ socket编程实例。包含客户端和服务端,可以实现客户端发送消息,服务端接收消息并写入日志。 server.cpp为服务端。 client.cpp为客户端。
  • c++ 游戏编程实例

    热门讨论 2012-08-25 06:29:10
    各种小游戏编程代码实例集锦 其中包括:五子棋 拼图,飞机等各种小游戏的代码还有可运行的编译程序....
  • Linux C++ socket编程实例

    千次阅读 2019-03-24 22:10:16
    再说一下select函数在server和client双向通信中的重要作用:网络编程的过程中,经常会遇到许多阻塞的函数,网络编程时使用的recv,recvfrom,connect函数都是阻塞的函数,当函数不能成功执行的时候,程序就会一直...
  • Visual C++ 6.0 编程实例与技巧.pdf
  • Visual C++ MFC编程实例教程

    千次下载 热门讨论 2014-02-15 13:45:12
    MFC实例教程和MFCwindows程序设计
  • C++ Socket编程实例解析

    万次阅读 2016-10-21 11:57:37
    socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。 在...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 189,496
精华内容 75,798
关键字:

c++编程实例

c++ 订阅