前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >C++の函数

C++の函数

作者头像
leoay
发布于 2020-01-14 08:26:58
发布于 2020-01-14 08:26:58
53900
代码可运行
举报
文章被收录于专栏:leoayleoay
运行总次数:0
代码可运行

C++の函数

续停更三天,让你们久等了,今天继续。今天我们开始了解C++中的函数的概念。

说到函数,我们应该比较清楚了,不论哪一门语言都有这个概念的,其实本质上就是讲我们之前介绍的语句,表达式等封装起来,形成一个功能单元。在C/C++中它也是程序执行的最小单元,我们新建一个工程,如果想要编译通过的话,必须要有一个主函数main。

但是在一个解释型语言,就不必要了,想js, shell,python等。以后,我们介绍的Go语言,也是编译型语言,也是需要main函数的,只不过形式不同而已。

函数的定义

首先,我们先说一下函数的定义方法,函数包括返回值,函数名,以及参数列表,返回值可以具有实际意义,也可以为void,参数列表呢,可以有,也可以没有。这个C/C++中没什么区别。下面举个例子怎么定义一个函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static BrewFunction GetBrewFunction(const caffe::string& name) {
  if (g_brew_map.count(name)) {
    return g_brew_map[name];
  } else {
    LOG(ERROR) << "Available caffe actions:";
    for (BrewMap::iterator it = g_brew_map.begin();
         it != g_brew_map.end(); ++it) {
      LOG(ERROR) << "\t" << it->first;
    }
    LOG(FATAL) << "Unknown action: " << name;
    return NULL;  // not reachable, just to suppress old compiler warnings.
  }
}

上面就是一个函数的例子,BrewFunction是返回值,GetBrewFunction是函数名,const caffe::string& name 是函数的参数列表。其实这部分代码是我从深度学习框架caffe中截取的一点。

我决定以后文章中的示例代码,我就从一些经典的开源项目中寻找吧,这样的话如果我们以后用到的话,可以更快熟悉,如果不用,也没太大关系,建议大家在学习完基础教程后,多去阅读一下开源代码,这样,我们的技能可以提升得更快。

参数列表的使用

我们在定义函数时,经常需要往一个函数里面传递参数。比如下面的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void Blob<Dtype>::Reshape(const BlobShape& shape) {
  CHECK_LE(shape.dim_size(), kMaxBlobAxes);
  vector<int> shape_vec(shape.dim_size());
  for (int i = 0; i < shape.dim_size(); ++i) {
    shape_vec[i] = shape.dim(i);
  }
  Reshape(shape_vec);
}

我要实现一个改变数据形状的函数,我就要传递一个BlobShape类型的参数, 可以看到上面这个参数shape也是一个BlobShape引用。我们把这成为传引用调用。如果是下面这样的,仅仅传一个值的话,我们称为“传值调用”。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void Blob<Dtype>::Reshape(const BlobShape shape) {
  CHECK_LE(shape.dim_size(), kMaxBlobAxes);
  vector<int> shape_vec(shape.dim_size());
  for (int i = 0; i < shape.dim_size(); ++i) {
    shape_vec[i] = shape.dim(i);
  }
  Reshape(shape_vec);
}

除了传引用,传值以外,我们的参数列表还可以传递指针,就是把一个对象或变量的地址传进去,传递指针可以实现和传递引用同样的功能,就是希望通过函数改变参数的值,然后能把这个值传出。这种用法很多很多。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void DataTransformer<Dtype>::Transform(const vector<cv::Mat> & mat_vector,
                                       Blob<Dtype>* transformed_blob) {
  const int mat_num = mat_vector.size();
  const int num = transformed_blob->num();
  const int channels = transformed_blob->channels();
  const int height = transformed_blob->height();
  const int width = transformed_blob->width();

  CHECK_GT(mat_num, 0) << "There is no MAT to add";
  CHECK_EQ(mat_num, num) <<
    "The size of mat_vector must be equals to transformed_blob->num()";
  Blob<Dtype> uni_blob(1, channels, height, width);
  for (int item_id = 0; item_id < mat_num; ++item_id) {
    int offset = transformed_blob->offset(item_id);
    uni_blob.set_cpu_data(transformed_blob->mutable_cpu_data() + offset);
    Transform(mat_vector[item_id], &uni_blob);
  }
}

看上面的transformed_blob,就是Blob<Dtype>类型的指针,我们可以在函数外面定义一个这个类型的变量,然后把它作为参数传入Transform函数,然后,我们就可以在函数中改变参数的值,最后把它传出去。

那么,从上面的例子中我们看到,函数中出现了const这个限定符,这里有什么用呢?这里const就是我们之前讲的,限定,不可更改。

就是说如果我们不打算在函数中修改传入的变量的话,最好把它用const加以限定,当然这不是必须的,这只是一个C++程序员的基本修养,一种编程习惯。当然,这也是非常有益处的。

比如,你要开发一个库给第三方调用,你不希望某个输入参数在代码运行时被更改,那么就应该使用const,强制限定。

除此以外,如果我们的参数比较大的话,也建议使用引用形参传递给参数,因为引用没有实体,是原输入数据的别名,不对数据进行拷贝,因此有更高的效率。

main函数获取命令行参数

很多情况下,我们会用到main函数获取命令行参数,那么这是怎么实现的呢?

我们先来看一下main函数的完整定义:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main(int argc, char * argv[])
{
    ...
}

上面的代码中,argc就是表示参数列表的个数,argv就是参数列表数组,假设我有一个test_func可执行文件,我在命令行执行下面的命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
test_func arg1 arg2 arg3 arg4 arg5

那么我们就可以在函数中读到argc的值为5,参数列表中的值分别为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
argv[0] = arg1
argv[1] = arg2
argv[2] = arg3
argv[3] = arg4
argv[4] = arg5

明天继续说C++中的函数

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 leoay 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
利用Caffe推理CenterNet(下篇)
此文章作为存档文章,caffe虽然不是c++版本运行CenterNet的最优方式,但也是一种选择。这里仅仅是记录,承接利用Caffe推理CenterNet(上篇)。
老潘
2023/10/19
2240
利用Caffe推理CenterNet(下篇)
caffe源码分析-DataTransformer
下面仅仅给出将Datum类型转化为caffe的Blob, cv::Mat的转化同理.
bear_fish
2019/02/25
5790
caffe源码分析-DataTransformer
caffe源码分析-inner_product_layer
本文主要分析caffe inner_product_layer源码,主要内容如下:
bear_fish
2019/02/25
7180
caffe源码分析-inner_product_layer
caffe源码分析-InputLayer
对于输入层,我们首先分析最简单的InputLayer层,其常作为网络inference时的输入,简单的mnist使用示例如下:
bear_fish
2019/02/25
6500
c++ mnist转化为opecv Mat
本文主要介绍如何使用C++将mnist 数据集转化为Opencv Mat,问题来源主要代码以及运行示例如下:
bear_fish
2019/02/25
5850
c++ mnist转化为opecv Mat
Caffe源码理解3:Layer基类与template method设计模式
层的概念在深度神经网络中占据核心位置,给定输入,数据在层间运算流动,最终输出结果。层定义了对数据如何操作,根据操作的不同,可以对层进行划分(具体参见Caffe Layers):
李拜六不开鑫
2018/12/27
6760
Caffe源码 - RoI Pooling 层
根据 prototxt 定义可以看出,roi_pool5 的输入有两个,bottom[0] 是 conv5 卷积层出来的 feature map,由于前面进行的 pool 层,conv5 的 feature map 的 height 和 width 分别是原图尺寸的 1/16. bottom[1] 是 rois blob, 其类似于一个 num_rois×5num\_rois × 5 的二维矩阵,行数 num_rosi 为 bottom[1]->num(),列数为 5,其定义为:
AIHGF
2019/02/18
8880
FFLIB之FFLUA——C++嵌入Lua&扩展Lua利器
摘要: 在使用C++做服务器开发中,经常会使用到脚本技术,Lua是最优秀的嵌入式脚本之一。Lua的轻量、小巧、概念之简单,都使他变得越来越受欢迎。本人也使用过python做嵌入式脚本,二者各有特点,关于python之后会写相关的文章,python对于我而言更喜欢用来编写工具,我前边一些相关的算法也是用python来实现的。今天主要讲Lua相关的开发技术。Lua具有如下特点: Lua 拥有虚拟机的概念,而其全部用标准C实现,不依赖任何库即可编译安装,更令人欣喜的是,整个Lua 的实现代码并不算多,可以直接继承
知然
2018/03/09
2.4K0
caffe源码分析-ReLULayer
激活函数如:ReLu,Sigmoid等layer相对较为简单,所以在分析InnerProductLayer前,我们先看下激活函数层。
bear_fish
2019/02/25
5660
caffe源码分析-ReLULayer
Caffe源码 - SegAccuracyLayer
SegAccuracyLayer 语义分割 seg_accuracy_layer.hpp #ifndef CAFFE_SEG_ACCURACY_LAYER_HPP_ #define CAFFE_SEG_ACCURACY_LAYER_HPP_ #include <vector> #include "caffe/blob.hpp" #include "caffe/common.hpp" #include "caffe/layer.hpp" #include "caffe/util/confusion
AIHGF
2019/02/18
6870
C++の自动类型推导和其他
本来这篇文章之前已经发过了技术◈C++核心知识总结(I),但是鉴于后来更新中断了,为了后面文章能连续更新,还是再发一遍吧。这篇文章主要讲以下三个话题:
leoay
2019/12/27
6650
C++ 宇宙穿越指南:小白从新手村到编程巅峰的奇幻之旅
这篇万字长文专为 C++ 小白打造。从 C++ 历史、应用领域讲起,详述学习环境搭建。由基础数据类型、控制流程,深入到类、模板等特性。搭配实践项目,给出学习方法与常见问题解法,助力小白全面掌握 C++,实现编程能力的飞跃 。
用户11458826
2025/03/21
540
Yolov8 pose关键点检测 C++ GPU部署:ONNXRuntime cuda部署
💡💡💡本文摘要:本文提供了YOLOv8 pose关键点检测 c++部署方式,ONNX Runtime CUDA和cpu部署
AI小怪兽
2024/08/14
1.3K0
Caffe2 - (九)MNIST 手写字体识别
Caffe2 - MNIST 手写字体识别 LeNet - CNN 网络训练; 采用 ReLUs 激活函数代替 Sigmoid. model helper import matplotlib.pyplot as plt import numpy as np import os import shutil import caffe2.python.predictor.predictor_exporter as pe from caffe2.python import core, model_helper
AIHGF
2019/02/18
2.5K0
caffe源码分析-DataLayer
DataLayer作为caffe训练时的数据层(以多线程的方式读取数据加速solver的训练过程),继承自BaseDataLayer/BasePrefetchingDataLayer。
bear_fish
2019/02/25
6540
caffe源码分析-DataLayer
Caffe Data层 - ImageDataLayer
Caffe Data 层 - ImageDataLayer Caffe 官方提供的直接从 image 文件读取图像数据及对应label. 1. 数据格式及 prototxt 定义 数据格式为: # train.txt 001.jpg 1 002.jpg 2 003.jpg 3 网络层定义: # train_val.prototxt layer { name: "data" type: "ImageData" top: "data" top: "label" i
AIHGF
2019/02/18
1.4K0
Caffe Data层  - ImageDataLayer
caffe源码分析-Blob
Blob 是Caffe作为数据传输的媒介,无论是网络权重参数,还是输入数据,都是转化为Blob数据结构来存储,网络,求解器等都是直接与此结构打交道的。
bear_fish
2019/02/25
2.1K1
caffe源码分析-Blob
Caffe源码 - SoftmaxWithLossLayer
SoftmaxWithLossLayer 针对 one-of-many 的分类任务计算 multinomial logistic loss,通过 softmax 来得到每一类的概率分布,传递实值预测(real-valued predictions).
AIHGF
2019/02/18
7220
caffe c++示例(mnist 多层感知机c++训练,测试)
caffe训练网络模型一般直接使用的caffe.bin: caffe train -solver solver.prototxt,其实这个命令的本质也是调用c++的Solver.
bear_fish
2019/02/25
1K0
caffe c++示例(mnist 多层感知机c++训练,测试)
Caffe实践 - 基于VGG16 多标签分类的训练与部署
假定每张图片具有 N 个标签(本文N=3),分别为 label1,label2,label3,...,labelNlabel1,label2,label3,...,labelN{label1, label2, label3,...,labelN}.
AIHGF
2019/02/18
1.4K0
Caffe实践 - 基于VGG16 多标签分类的训练与部署
相关推荐
利用Caffe推理CenterNet(下篇)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文