x265探索与研究(六):main()函数

x265源代码的入口函数是main(),本文分析main()的主要功能。

首先给出main()函数的功能及其代码结构;其次给出main()函数源代码以及分析;最后给出main()函数中的主要功能函数的详细功能。

1、main()函数的功能及其代码结构

main()函数的主要功能是解析參数并进行编码的一些准备工作,调用了例如以下几个重要的函数:

(1)cliopt.parse()函数:解析參数

(2)api->encoder_open()函数:打开编码器配置

(3)api->encoder_headers()函数:设置NAL相关信息

(4)api->encoder_encode()函数:进入编码函数

(5)api->encoder_close()函数:结束编码并进行总结

注:encoder_open()函数、encoder_headers()函数、encoder_encode()函数与encoder_close()函数均位于api.app中。

相应的函数关系图例如以下图所看到的:

2、main()函数源代码以及分析

main()函数的源代码分析例如以下代码中的凝视。代码例如以下:

/*=============================================================*/
/*
====== Analysed by: RuiDong Fang
====== Csdn Blog: http://blog.csdn.net/frd2009041510
====== Date: 2016.04.10
====== Funtion: x265的入口main()函数
*/
/*=============================================================*/
/* CLI return codes:
*
* 0 - encode successful
* 1 - unable to parse command line
* 2 - unable to open encoder
* 3 - unable to generate stream headers
* 4 - encoder abort
* 5 - unable to open csv file
*
*/
int main(int argc, char **argv) //主函数入口
{
#if HAVE_VLD
// This uses Microsoft's proprietary WCHAR type, but this only builds on Windows to start with
VLDSetReportOptions(VLD_OPT_REPORT_TO_DEBUGGER | VLD_OPT_REPORT_TO_FILE, L"x265_leaks.txt");
#endif
PROFILE_INIT();
THREAD_NAME("API", 0); GetConsoleTitle(orgConsoleTitle, CONSOLE_TITLE_SIZE); //获取控制台窗体
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED); ReconPlay* reconPlay = NULL;
CLIOptions cliopt; if (cliopt.parse(argc, argv)) //==========分析參数。对编码器的參数进行设定,打开文件
{
cliopt.destroy();
if (cliopt.api)
cliopt.api->param_free(cliopt.param);
exit(1);
} x265_param* param = cliopt.param;
const x265_api* api = cliopt.api; /* This allows muxers to modify bitstream format */
cliopt.output->setParam(param); if (cliopt.reconPlayCmd)
reconPlay = new ReconPlay(cliopt.reconPlayCmd, *param); /* note: we could try to acquire a different libx265 API here based on
* the profile found during option parsing, but it must be done before
* opening an encoder */ x265_encoder *encoder = api->encoder_open(param); //==========encoder_open()函数,打印编码器配置
if (!encoder) //若打不开编码器配置。提示错误
{
x265_log(param, X265_LOG_ERROR, "failed to open encoder\n");
cliopt.destroy();
api->param_free(param);
api->cleanup();
exit(2);
} /* get the encoder parameters post-initialization */
api->encoder_parameters(encoder, param); if (cliopt.csvfn)
{
cliopt.csvfpt = x265_csvlog_open(*api, *param, cliopt.csvfn, cliopt.csvLogLevel);
if (!cliopt.csvfpt)
{
x265_log(param, X265_LOG_ERROR, "Unable to open CSV log file <%s>, aborting\n", cliopt.csvfn);
cliopt.destroy();
if (cliopt.api)
cliopt.api->param_free(cliopt.param);
exit(5);
}
} /* Control-C handler */
//当键入Ctrl-C的时候,当前运行程序调用指针函数sigint_handler 运行完后,再返回原来运行的地方接着往下走。 if (signal(SIGINT, sigint_handler) == SIG_ERR)
x265_log(param, X265_LOG_ERROR, "Unable to register CTRL+C handler: %s\n", strerror(errno)); x265_picture pic_orig, pic_out; //定义x265的输入pic_orig和输出pic_out
x265_picture *pic_in = &pic_orig; //获取x265的输入pic_orig的地址 /* Allocate recon picture if analysisMode is enabled */
std::priority_queue<int64_t>* pts_queue = cliopt.output->needPTS() ? new std::priority_queue<int64_t>() : NULL;
x265_picture *pic_recon = (cliopt.recon || !!param->analysisMode || pts_queue || reconPlay || cliopt.csvLogLevel) ? &pic_out : NULL; uint32_t inFrameCount = 0; //输入的帧数
uint32_t outFrameCount = 0; //输出的帧数 x265_nal *p_nal;
x265_stats stats;
uint32_t nal;
int16_t *errorBuf = NULL;
int ret = 0; if (!param->bRepeatHeaders)
{
if (api->encoder_headers(encoder, &p_nal, &nal) < 0) //==========encoder_headers函数
{
x265_log(param, X265_LOG_ERROR, "Failure generating stream headers\n");
ret = 3;
goto fail;
}
else
cliopt.totalbytes += cliopt.output->writeHeaders(p_nal, nal);
} api->picture_init(param, pic_in); if (cliopt.bDither)
{
errorBuf = X265_MALLOC(int16_t, param->sourceWidth + 1);
if (errorBuf)
memset(errorBuf, 0, (param->sourceWidth + 1) * sizeof(int16_t));
else
cliopt.bDither = false;
} // main encoder loop(编码主循环)
while (pic_in && !b_ctrl_c)
{
pic_orig.poc = inFrameCount;
if (cliopt.qpfile)
{
if (!cliopt.parseQPFile(pic_orig))
{
x265_log(NULL, X265_LOG_ERROR, "can't parse qpfile for frame %d\n", pic_in->poc);
fclose(cliopt.qpfile);
cliopt.qpfile = NULL;
}
} //当输入帧将要所有编码且输入的帧数大于或等于将要编码的帧数
if (cliopt.framesToBeEncoded && inFrameCount >= cliopt.framesToBeEncoded)
pic_in = NULL;
else if (cliopt.input->readPicture(pic_orig)) //每读入一帧
inFrameCount++; //输入的帧数自加1
else
pic_in = NULL; if (pic_in)
{
if (pic_in->bitDepth > param->internalBitDepth && cliopt.bDither)
{
x265_dither_image(*api, *pic_in, cliopt.input->getWidth(), cliopt.input->getHeight(), errorBuf, param->internalBitDepth);
pic_in->bitDepth = param->internalBitDepth;
}
/* Overwrite PTS */
pic_in->pts = pic_in->poc;
}
//进行编码的入口函数,读入24帧后才開始编码
int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, pic_in, pic_recon); //==========encoder_encode()函数。numEncoded是将要编码的帧数
if (numEncoded < 0)
{
b_ctrl_c = 1;
ret = 4;
break;
} if (reconPlay && numEncoded)
reconPlay->writePicture(*pic_recon); outFrameCount += numEncoded; if (numEncoded && pic_recon && cliopt.recon)
cliopt.recon->writePicture(pic_out);
if (nal)
{
cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
if (pts_queue)
{
pts_queue->push(-pic_out.pts);
if (pts_queue->size() > 2)
pts_queue->pop();
}
} cliopt.printStatus(outFrameCount); //打印编码帧的详细信息
if (numEncoded && cliopt.csvLogLevel)
x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon, cliopt.csvLogLevel);
} /* Flush the encoder */
/*功能:前面读入24帧后才開始编码,此处事实上就是处理相应的倒数的24帧,将其存储*/
while (!b_ctrl_c) //退出上一个大循环后且没有按下Ctrl+C,代码继续运行
{
//==========encoder_encode()函数
int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, NULL, pic_recon);
if (numEncoded < 0)
{
ret = 4;
break;
} if (reconPlay && numEncoded)
reconPlay->writePicture(*pic_recon); outFrameCount += numEncoded;
if (numEncoded && pic_recon && cliopt.recon)
cliopt.recon->writePicture(pic_out);
if (nal)
{
cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
if (pts_queue)
{
pts_queue->push(-pic_out.pts);
if (pts_queue->size() > 2)
pts_queue->pop();
}
} cliopt.printStatus(outFrameCount);
if (numEncoded && cliopt.csvLogLevel)
x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon, cliopt.csvLogLevel); if (!numEncoded)
break;
} /* clear progress report */
if (cliopt.bProgress)
fprintf(stderr, "%*s\r", 80, " "); fail: delete reconPlay; api->encoder_get_stats(encoder, &stats, sizeof(stats));
if (cliopt.csvfpt && !b_ctrl_c)
x265_csvlog_encode(cliopt.csvfpt, *api, *param, stats, cliopt.csvLogLevel, argc, argv);
api->encoder_close(encoder); //==========encoder_close()函数 int64_t second_largest_pts = 0;
int64_t largest_pts = 0;
if (pts_queue && pts_queue->size() >= 2)
{
second_largest_pts = -pts_queue->top();
pts_queue->pop();
largest_pts = -pts_queue->top();
pts_queue->pop();
delete pts_queue;
pts_queue = NULL;
}
cliopt.output->closeFile(largest_pts, second_largest_pts); if (b_ctrl_c) //按下Ctrl+C,直接退出
general_log(param, NULL, X265_LOG_INFO, "aborted at input frame %d, output frame %d\n",
cliopt.seek + inFrameCount, stats.encodedPictureCount); api->cleanup(); /* Free library singletons */ cliopt.destroy(); api->param_free(param); X265_FREE(errorBuf); SetConsoleTitle(orgConsoleTitle); //设置控制窗体标题
SetThreadExecutionState(ES_CONTINUOUS); #if HAVE_VLD
assert(VLDReportLeaks() == 0);
#endif return ret;
}

3、main()函数中的部分功能函数的详细功能

3.1、GetConsoleTitle(orgConsoleTitle, CONSOLE_TITLE_SIZE);

GetConsoleTitle的主要功能是获取控制台窗体。当中orgConsoleTitle指向一个缓冲区指针以接收包括标题的字符串。CONSOLE_TITLE_SIZE)是由orgConsoleTitle指向的缓冲区大小。假设函数成功。则返回值是以字符为单位的长度控制台窗体的标题;假设该函数失败,则返回值为零。要获取错误信息。能够调用GetLastError 。

3.2、cliopt.parse(argc, argv)

cliopt.parse(argc, argv)的主要功能是分析參数,直接调用x265.cpp中的bool CLIOptions::parse(int argc, char **argv)函数,该函数会打印输入视频的分辨率、帧率、视频格式、所要编码的帧数目以及输出文件名等。例如以下图所看到的:

相应的代码例如以下:

bool CLIOptions::parse(int argc, char **argv)
{
bool bError = false;
int bShowHelp = false;
int inputBitDepth = 8;
int outputBitDepth = 0;
int reconFileBitDepth = 0;
const char *inputfn = NULL;
const char *reconfn = NULL;
const char *outputfn = NULL;
const char *preset = NULL;
const char *tune = NULL;
const char *profile = NULL; if (argc <= 1)
{
x265_log(NULL, X265_LOG_ERROR, "No input file. Run x265 --help for a list of options.\n");
return true;
} /* Presets are applied before all other options. */
for (optind = 0;; )
{
int c = getopt_long(argc, argv, short_options, long_options, NULL);
if (c == -1)
break;
else if (c == 'p')
preset = optarg;
else if (c == 't')
tune = optarg;
else if (c == 'D')
outputBitDepth = atoi(optarg);
else if (c == 'P')
profile = optarg;
else if (c == '? ')
bShowHelp = true;
} if (!outputBitDepth && profile)
{
/* try to derive the output bit depth from the requested profile */
if (strstr(profile, "10"))
outputBitDepth = 10;
else if (strstr(profile, "12"))
outputBitDepth = 12;
else
outputBitDepth = 8;
} api = x265_api_get(outputBitDepth);
if (!api)
{
x265_log(NULL, X265_LOG_WARNING, "falling back to default bit-depth\n");
api = x265_api_get(0);
} param = api->param_alloc();
if (!param)
{
x265_log(NULL, X265_LOG_ERROR, "param alloc failed\n");
return true;
} if (api->param_default_preset(param, preset, tune) < 0)
{
x265_log(NULL, X265_LOG_ERROR, "preset or tune unrecognized\n");
return true;
} if (bShowHelp)
{
printVersion(param, api);
showHelp(param);
} for (optind = 0;; )
{
int long_options_index = -1;
int c = getopt_long(argc, argv, short_options, long_options, &long_options_index);
if (c == -1)
break; switch (c)
{
case 'h':
printVersion(param, api);
showHelp(param);
break; case 'V':
printVersion(param, api);
x265_report_simd(param);
exit(0); default:
if (long_options_index < 0 && c > 0)
{
for (size_t i = 0; i < sizeof(long_options) / sizeof(long_options[0]); i++)
{
if (long_options[i].val == c)
{
long_options_index = (int)i;
break;
}
} if (long_options_index < 0)
{
/* getopt_long might have already printed an error message */
if (c != 63)
x265_log(NULL, X265_LOG_WARNING, "internal error: short option '%c' has no long option\n", c);
return true;
}
}
if (long_options_index < 0)
{
x265_log(NULL, X265_LOG_WARNING, "short option '%c' unrecognized\n", c);
return true;
}
#define OPT(longname) \
else if (!strcmp(long_options[long_options_index].name, longname))
#define OPT2(name1, name2) \
else if (!strcmp(long_options[long_options_index].name, name1) || \
!strcmp(long_options[long_options_index].name, name2)) if (0) ;
OPT2("frame-skip", "seek") this->seek = (uint32_t)x265_atoi(optarg, bError);
OPT("frames") this->framesToBeEncoded = (uint32_t)x265_atoi(optarg, bError);
OPT("csv") this->csvfn = optarg;
OPT("csv-log-level") this->csvLogLevel = x265_atoi(optarg, bError);
OPT("no-progress") this->bProgress = false;
OPT("output") outputfn = optarg;
OPT("input") inputfn = optarg;
OPT("recon") reconfn = optarg;
OPT("input-depth") inputBitDepth = (uint32_t)x265_atoi(optarg, bError);
OPT("dither") this->bDither = true;
OPT("recon-depth") reconFileBitDepth = (uint32_t)x265_atoi(optarg, bError);
OPT("y4m") this->bForceY4m = true;
OPT("profile") /* handled above */;
OPT("preset") /* handled above */;
OPT("tune") /* handled above */;
OPT("output-depth") /* handled above */;
OPT("recon-y4m-exec") reconPlayCmd = optarg;
OPT("qpfile")
{
this->qpfile = fopen(optarg, "rb");
if (!this->qpfile)
{
x265_log(param, X265_LOG_ERROR, "%s qpfile not found or error in opening qp file\n", optarg);
return false;
}
}
else
bError |= !!api->param_parse(param, long_options[long_options_index].name, optarg); if (bError)
{
const char *name = long_options_index > 0 ? long_options[long_options_index].name : argv[optind - 2];
x265_log(NULL, X265_LOG_ERROR, "invalid argument: %s = %s\n", name, optarg);
return true;
}
#undef OPT
}
} if (optind < argc && !inputfn)
inputfn = argv[optind++];
if (optind < argc && !outputfn)
outputfn = argv[optind++];
if (optind < argc)
{
x265_log(param, X265_LOG_WARNING, "extra unused command arguments given <%s>\n", argv[optind]);
return true;
} if (argc <= 1)
{
api->param_default(param);
printVersion(param, api);
showHelp(param);
} if (!inputfn || !outputfn)
{
x265_log(param, X265_LOG_ERROR, "input or output file not specified, try --help for help\n");
return true;
} if (param->internalBitDepth != api->bit_depth)
{
x265_log(param, X265_LOG_ERROR, "Only bit depths of %d are supported in this build\n", api->bit_depth);
return true;
} InputFileInfo info;
info.filename = inputfn;
info.depth = inputBitDepth;
info.csp = param->internalCsp;
info.width = param->sourceWidth;
info.height = param->sourceHeight;
info.fpsNum = param->fpsNum;
info.fpsDenom = param->fpsDenom;
info.sarWidth = param->vui.sarWidth;
info.sarHeight = param->vui.sarHeight;
info.skipFrames = seek;
info.frameCount = 0;
getParamAspectRatio(param, info.sarWidth, info.sarHeight); this->input = InputFile::open(info, this->bForceY4m);
if (!this->input || this->input->isFail())
{
x265_log(param, X265_LOG_ERROR, "unable to open input file <%s>\n", inputfn);
return true;
} if (info.depth < 8 || info.depth > 16)
{
x265_log(param, X265_LOG_ERROR, "Input bit depth (%d) must be between 8 and 16\n", inputBitDepth);
return true;
} /* Unconditionally accept height/width/csp from file info */
param->sourceWidth = info.width;
param->sourceHeight = info.height;
param->internalCsp = info.csp; /* Accept fps and sar from file info if not specified by user */
if (param->fpsDenom == 0 || param->fpsNum == 0)
{
param->fpsDenom = info.fpsDenom;
param->fpsNum = info.fpsNum;
}
if (!param->vui.aspectRatioIdc && info.sarWidth && info.sarHeight)
setParamAspectRatio(param, info.sarWidth, info.sarHeight);
if (this->framesToBeEncoded == 0 && info.frameCount > (int)seek)
this->framesToBeEncoded = info.frameCount - seek;
param->totalFrames = this->framesToBeEncoded; /* Force CFR until we have support for VFR */
info.timebaseNum = param->fpsDenom;
info.timebaseDenom = param->fpsNum; if (api->param_apply_profile(param, profile))
return true; if (param->logLevel >= X265_LOG_INFO)
{
char buf[128];
int p = sprintf(buf, "%dx%d fps %d/%d %sp%d", param->sourceWidth, param->sourceHeight,
param->fpsNum, param->fpsDenom, x265_source_csp_names[param->internalCsp], info.depth); int width, height;
getParamAspectRatio(param, width, height);
if (width && height)
p += sprintf(buf + p, " sar %d:%d", width, height); if (framesToBeEncoded <= 0 || info.frameCount <= 0)
strcpy(buf + p, " unknown frame count");
else
sprintf(buf + p, " frames %u - %d of %d", this->seek, this->seek + this->framesToBeEncoded - 1, info.frameCount); general_log(param, input->getName(), X265_LOG_INFO, "%s\n", buf);
} this->input->startReader(); if (reconfn)
{
if (reconFileBitDepth == 0)
reconFileBitDepth = param->internalBitDepth;
this->recon = ReconFile::open(reconfn, param->sourceWidth, param->sourceHeight, reconFileBitDepth,
param->fpsNum, param->fpsDenom, param->internalCsp);
if (this->recon->isFail())
{
x265_log(param, X265_LOG_WARNING, "unable to write reconstructed outputs file\n");
this->recon->release();
this->recon = 0;
}
else
general_log(param, this->recon->getName(), X265_LOG_INFO,
"reconstructed images %dx%d fps %d/%d %s\n",
param->sourceWidth, param->sourceHeight, param->fpsNum, param->fpsDenom,
x265_source_csp_names[param->internalCsp]);
} this->output = OutputFile::open(outputfn, info);
if (this->output->isFail())
{
x265_log(param, X265_LOG_ERROR, "failed to open output file <%s> for writing\n", outputfn);
return true;
}
general_log(param, this->output->getName(), X265_LOG_INFO, "output file: %s\n", outputfn);
return false; //完毕后返回false
}

3.3、encoder_open()函数

encoder_open(param)的主要功能是打印编码器的配置信息,直接调用api.cpp中的x265_encoder *x265_encoder_open(x265_param *p),该函数中调用了x265_print_params(param)用以打印编码器配置信息,例如以下图所看到的:

相应的代码例如以下:

x265_encoder *x265_encoder_open(x265_param *p)
{
if (!p)
return NULL; #if _MSC_VER
#pragma warning(disable: 4127) // conditional expression is constant, yes I know
#endif #if HIGH_BIT_DEPTH
if (X265_DEPTH == 12)
x265_log(p, X265_LOG_WARNING, "Main12 is HIGHLY experimental, do not use!\n");
else if (X265_DEPTH != 10 && X265_DEPTH != 12)
#else
if (X265_DEPTH != 8)
#endif
{
x265_log(p, X265_LOG_ERROR, "Build error, internal bit depth mismatch\n");
return NULL;
} Encoder* encoder = NULL;
x265_param* param = PARAM_NS::x265_param_alloc();
x265_param* latestParam = PARAM_NS::x265_param_alloc();
if (!param || !latestParam)
goto fail; memcpy(param, p, sizeof(x265_param));
x265_log(param, X265_LOG_INFO, "HEVC encoder version %s\n", PFX(version_str));
x265_log(param, X265_LOG_INFO, "build info %s\n", PFX(build_info_str)); x265_setup_primitives(param); if (x265_check_params(param))
goto fail; if (x265_set_globals(param))
goto fail; encoder = new Encoder;
if (!param->rc.bEnableSlowFirstPass)
PARAM_NS::x265_param_apply_fastfirstpass(param); // may change params for auto-detect, etc
encoder->configure(param);
// may change rate control and CPB params
if (!enforceLevel(*param, encoder->m_vps))
goto fail; // will detect and set profile/tier/level in VPS
determineLevel(*param, encoder->m_vps); if (!param->bAllowNonConformance && encoder->m_vps.ptl.profileIdc == Profile::NONE)
{
x265_log(param, X265_LOG_INFO, "non-conformant bitstreams not allowed (--allow-non-conformance)\n");
goto fail;
} encoder->create();
encoder->m_latestParam = latestParam;
memcpy(latestParam, param, sizeof(x265_param));
if (encoder->m_aborted)
goto fail; x265_print_params(param); //打印參数
return encoder; fail:
delete encoder;
PARAM_NS::x265_param_free(param);
PARAM_NS::x265_param_free(latestParam);
return NULL;
}

3.4、encoder_headers()函数

int x265_encoder_headers(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal)
{
if (pp_nal && enc)
{
Encoder *encoder = static_cast<Encoder*>(enc);
Entropy sbacCoder;
Bitstream bs;
encoder->getStreamHeaders(encoder->m_nalList, sbacCoder, bs); //get Stream Headers
*pp_nal = &encoder->m_nalList.m_nal[0];
if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
return encoder->m_nalList.m_occupancy;
} return -1;
}

3.5、encoder_encode()函数

int x265_encoder_encode(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal, x265_picture *pic_in, x265_picture *pic_out)
{
if (!enc)
return -1; Encoder *encoder = static_cast<Encoder*>(enc);
int numEncoded; // While flushing, we cannot return 0 until the entire stream is flushed
do
{
numEncoded = encoder->encode(pic_in, pic_out); //==========进入编码函数
}
while (numEncoded == 0 && !pic_in && encoder->m_numDelayedPic); // do not allow reuse of these buffers for more than one picture. The
// encoder now owns these analysisData buffers.
if (pic_in)
{
pic_in->analysisData.intraData = NULL;
pic_in->analysisData.interData = NULL;
} if (pp_nal && numEncoded > 0)
{
*pp_nal = &encoder->m_nalList.m_nal[0];
if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
}
else if (pi_nal)
*pi_nal = 0; return numEncoded;
}

3.6、encoder_close()函数

void x265_encoder_close(x265_encoder *enc)
{
if (enc)
{
Encoder *encoder = static_cast<Encoder*>(enc); encoder->stopJobs();
encoder->printSummary(); //==========打印总结信息
encoder->destroy();
delete encoder;
ATOMIC_DEC(&g_ctuSizeConfigured);
}
}

到这儿。main()函数的主要功能就分析完成了。

x265探索与研究(六):main()函数的更多相关文章

  1. x265探索与研究(四):怎样编码视频?

    怎样编码视频?           本文介绍x265中的两种编码视频方法,一是採用命令行的方法.二是GUI的方式.   1.命令行的方法   (1).第一种方式生成*.265格式的视频文件       ...

  2. [汇编与C语言关系]2. main函数与启动例程

    为什么汇编程序的入口是_start,而C程序的入口是main函数呢?以下就来解释这个问题 在<x86汇编程序基础(AT&T语法)>一文中我们汇编和链接的步骤是: $ as hell ...

  3. SequoiaDB 系列之五 :源码分析之main函数

    好久好久没有写博客了,因为一直要做各种事,工作上的,生活上的,这一下就是半年. 时光如梭. 这两天回头看了看写的博客,感觉都是贻笑大方. 但是还是想坚持把SequoiaDB系列写完. 初步的打算已经确 ...

  4. atexit注册的函数是在main函数之后执行?

    跟atexit函数相识已久,man手册里对atexit的解释是这么一段: The atexit() function registers the given function to be called ...

  5. main函数和启动例程

    为什么汇编程序的入口是_start,而C程序的入口是main函数呢?本节就来解释这个问题.在讲例 18.1 “最简单的汇编程序”时,我们的汇编和链接步骤是: $ as hello.s -o hello ...

  6. static关键字的用法和main函数

    一.static关键字:静态的,它可以修饰成员变量和成员方法 1.修饰成员变量的情况,当类所属对象中存在共享数据时,我们就可以把数据对应的属性定义为静态的,这里的共享数据是对象数据相同,而不是拥有相同 ...

  7. 为什么c程序里一定要写main函数

    一. 学习过程 编写程序f.c: 对其进行编译,正常通过,再对其进行连接,出现错误: 显示的出错信息为: 翻译成中文是:在c0s模块没有定义符号’_main’. 那么这个错误信息可能与文件c0s.ob ...

  8. 菜鸟nginx源码剖析 框架篇(一) 从main函数看nginx启动流程(转)

    俗话说的好,牵牛要牵牛鼻子 驾车顶牛,处理复杂的东西,只要抓住重点,才能理清脉络,不至于深陷其中,不能自拔.对复杂的nginx而言,main函数就是“牛之鼻”,只要能理清main函数,就一定能理解其中 ...

  9. PostgreSQL启动main函数都干了什么(一)

    DB Version:9.5.3 环境:CentOS7.x 调试工具:GDB source:src/backend/main/main.c 56 /* 57 * Any Postgres server ...

随机推荐

  1. HDU 1978 How many ways DP问题

    How many ways Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...

  2. js arguments 内置对象

    1.arguments是js的内置对象. 2.在不确定对象是可以用来重载函数. 3.用法如下: function goTo() { var i=arguments.length; alert(i); ...

  3. mysql update语句添加表关联查询

    UPDATE tab_game_version  as a INNER JOIN tab_game_version as b ON a.id=b.idSET a.advert_data=0 where ...

  4. (译)Getting Started——1.3.3 Working with Foundation(使用Foundation框架)

    在你使用Objective-C语言开发应用时,你会发现在开发中,你会用到很多框架.尤其是Foundation框架,该框架为应用提供了最基础的服务.Foundation框架包括了代表着基本数据类型的va ...

  5. C语言 函数指针二(正向调用)

    //函数指针做函数参数 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<Wi ...

  6. ApexSql Log 2016破解版&补丁

    绿色破解版: http://download.csdn.net/detail/gsyifan/9316993 官网: https://www.apexsql.com/sql_tools_log.asp ...

  7. Openstack(Kilo)安装系列之Keystone(四)

    创建租间.用户.角色 一.To configure prerequisites 1.Configure the authentication token: export OS_TOKEN=ADMIN_ ...

  8. MFC多国语言——资源副本

    此随笔主要参考了http://www.cnblogs.com/xianyunhe/archive/2011/09/02/2163842.html 为软件提供多国语言的支持的具体实现方法有很多,但基本原 ...

  9. 鱼眼镜头的distortion校正【matlab】

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 作者:WWC %%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%% ...

  10. Django实现组合搜索的方法示例

    目录 一.实现方法 二.基本原理 三.代码样例 方法1:纯模板语言实现 方法二:使用simpletag实现 四.其他变化 1.model定义 2.处理函数变化 3.simpletag相应改变   一. ...