在Linux C/C++程序中打印日志时,可能会由于需要打印未知个数的变量参数,那么vsnprintf函数就排上用场了。这里使用一个简单的C程序例子,演示在打印源程序文件名和该打印函数所在的行号的同时,使用vsnprintf函数打印个数未知的参数变量。
在编程中,需要关注snprintf()的两个问题:一是它的返回值,二是它的第二个参数。
写C程序的时候,printf输出调试信息是常态,printf输出调试信息时如果能自动带源码信息(__FILE__,__FUNCTION__, __LINE__),显然更方便查找问题,如果能再加上时间戳就更完美了。 如果到处都用printf("%s:%s:%d, %s\n",__FILE__,__FUNCTION__, __LINE__,"hello")写起来也太麻烦了;而且有的时候还需要向内存缓冲区打印输出。而且__FILE__提供的是源码的全路径名,打印实可能会很长。 所以这种直接在代码写printf("%s:%s:%d, %s\n",__FILE__,__FUNCTION__, __LINE__,"hello")语句的方式在实际开发中用起来是很麻烦的。
Visual Studio2015编译中出现此问题:error LNK2019: 无法解析的外部符号 __vsnprintf,该符号在函数xxxx中被引用
最近做一个C语言的嵌入式项目,需要分段向指定内存调用vsnprintf输出不定长度的格式化输出,因为是分段输出,而且长度不定,所以一开始就不能分配固定长度内存,每次输出都要从输出到上次的结尾开始,所以还要记录每次的输出长度。还是Java开发方便,有现成的StringBuffer可以用,不停的向StringBuffer调用 append添加就好了,哪有这么麻烦。 为了解决这个麻烦,我参照Java中的StringBuffer对象,实现了一个 stringbuffer,并基于它实现bufprintf函数可以向stringbuffer格式化输出,调用时就不需要再考虑自动分配内存和偏移量的问题了。
尽管说define有很多不足之处,很多时候我们需要使用const来替代define, 也可以使用typedef来替代define。
1. 概述 相比各种打断点调试的办法,还是更习惯使用打印输出来进行调试。 2. 详论 2.1. 代码 这里写了三个函数:分别是输出到屏幕,输出到警告日志,输出错误日志。 Output.h: #pragma once namespace Output { void PrintScreen(const char* lpszFormat, ...); void PrintLogWarning(const char* lpszFormat, ...); void PrintLogError(const
尽管说define有很多不足之处,很多时候我们需要使用const来替代define, 也可以使用typedef来替代define。 但是,在一些实际工程中,我们还是不可避免的使用到了define,这给我们带来了极大的方便。 1 定义头文件,防止重复包含 其实不是真正的防止重复包含头文件,而是忽略除了第一次之外的其他包含: http://blog.csdn.net/wangshubo1989/article/details/48310681 #ifndef WANGSHUBO_BASE_H_ #defin
标准C语言函数snprintf,vsnprintf系列函数可以向指定的缓冲区输出格式化打印的字符串。 如果指定的缓存区足够大,那么调用正常,返回值就是写入缓存区的字节长度(不含结尾'\0') 那么缓存区不够大的情况呢? 本文要说的是这系列函数的在缓存区长度不足以输出所有内容时的返回值在不同一编译器提供的实现表现是不同的。 我们用如下一段简单的测试代码来验证其返回值表现。
LNK2001 无法解析的外部符号 __except_handler4_common msvcrt.lib
诚实点,并不是假设读的人C语言基础很差,而事实是,自己的C语言基础实在太差,要补学基础知识之后才可以进行后续的学习,惭愧!
平时公司的代码安全扫描会给出不安全代码的告警,其中会检查代码中间的strcpy和sprintf函数,而要求使用strncpy和snprintf。今天我们讨论一下怎样写出完美的snprintf。 snprintf是一个在C99才被加入如标准的函数,原来的各个编译器都有自己的实现,至少.NET2003编译器还要是使用_snprintf这样的函数名称。 而这些编译器间都有差异,而且Glibc库又有自己的不同的实现。 查询一下snprintf的函数的MSDN说明。如下: Let len be the length
有关snprintf返回值更多信息,请参考:http://bbs.hadoopor.com/thread-1185-1-1.html
对于一款游戏引擎来说,支持显示字体自然是必备的功能,HGE内建的字体功能虽然仅支持一般的位图字体,但是也算是简洁明了,这次的HGE源码之旅就让我们来看一看他的各中实现:)
使用tgt-1.0.75创建好target之后,在initiator端执行login操作大约卡3s~5s左右。同时观察tgt,CPU消耗到达100%。
_iob_func这个只能在一个文件中定义一次,如果定义两次 ,会出现__iob_func已经在 Commands.obj 中定义的错误
Formatted I/O /* ANSI */ /* write a formatted string to the standard output stream */ int printf(char *, ...); /* write a formatted string to a buffer */ int sprintf(char *, char *, ...); /* write a formatted string to a buffer, not exceeding buffer
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
root@localhost:~# tar zxvf zlib-1.2.3.tar.gz
概述 广告粗排训练是一个小模型、低延时的业务场景。在此场景下,我们基于于云帆Oteam中的Light通用训练加速框架,根据广告粗排训练特性定制化地构建了GPU上同步分布式的模式进行数据并行的训练模式,将存储在HDFS上的训练数据,读取到本地,然后输入到模型中,进行前向计算。该训练方式不存在PS,每个worker上有全量的参数。Light框架下的各个worker前向计算获得梯度后,使用LightCC进行梯度规约通信,并将获得的梯度更新到本地的参数上。我们在上述训练方式下,进行了系统瓶颈分析和性能优化。本系列
听说C/S客户端的安全测试很少出现测试流程的。洛米唯熊百度一找,谷歌一搜。果然。没有正规的测试流程。偶然在一个群里看到一个图,感觉还可以,就自己摸索的尝试对应的流程写一下找到的工具给各位大佬做一下分享。
在C和C++中,变参格式化函数虽然非类型安全,但却十分便利,因为得到广泛使用。对于常见的size_t类型要用“%zu”,ssize_t用”%zd“,int64_t用“% ”PRId64,uint64_t用“% ”PRIu64,long用"%ld",long long用"%lld",示例: const int64_t datetime = INT64_C(20190124144930); printf("datetime: %" PRId64"\n", datetime); 注意在PRId64前保留一个空格,以避免编译警告 format_string源代码链接: https://github.com/eyjian/r3c/blob/master/utils.cpp https://github.com/eyjian/libmooon/blob/master/src/utils/string_utils.cpp format_string源代码:
"缓冲区溢出"漏洞是一个由来已久的漏洞类型,虽然现代操作系统的编译器,已经可以很大程度的阻止此类型漏洞的出现,但是作为一名合格的C程序员,还是有必要对此类漏洞的原理进行一定了解的,今天我就带大家对此类漏洞进行分析。
基本所有的编程语言都会有异常捕捉的语法,try-catch 基本是所有编程语言都会有的信息,他会捕捉 try 中语法错误,如果存在语法错误就会执行 catch 的内容。
func( Type para1, Type para2, Type para3, ... ) { /****** Step 1 ******/ va_list ap; va_start( ap, para3 ); //一定要“...”之前的那个参数**ap指向para后的第一个可变参数。 /****** Step 2 ******/ //此时ap指向第一个可变参数 //调用va_arg取得里面的值 Type xx = va_arg( ap, Type ); //Type一定要相同,如: //char *p = va_arg( ap, char *); //int i = va_arg( ap, int ); //如果有多个参数继续调用va_arg /****** Step 3 ******/ va_end(ap); //For robust! } ◎研究: typedef char * va_list;//va_list 等价于char*即字符指针。 #define va_start _crt_va_start//注意下面的替代。 #define va_arg _crt_va_arg #define va_end _crt_va_end #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define _crt_va_end(ap) ( ap = (va_list)0 ) va_list argptr; C语言的函数是从右向左压入堆栈的,调用va_start后, 按定义的宏运算,_ADDRESSOF得到v所在的地址,然后这个 地址加上v的大小,则使ap指向第一个可变参数如图: 栈底 高地址 | ....... | 函数返回地址 | ....... | 函数最后一个参数 | .... | 函数第一个可变参数 <--va_start后ap指向 | 函数最后一个固定参数 | 函数第一个固定参数 栈顶 低地址 然后,用va_arg()取得类型t的可变参数值, 先是让ap指向下一个参数: ap += _INTSIZEOF(t),然后在减去_INTSIZEOF(t),使得表达式结果为 ap之前的值,即当前需要得到的参数的地址,强制转换成指向此参数的 类型的指针,然后用*取值 最后,用va_end(ap),给ap初始化,保持健壮性。 example:(chenguiming) #include <stdio.h> #include <ctype.h> #include<stdlib.h> #include <stdarg.h> int average( int first, ... ) //变参数函数,C++里也有 **…表明后面有好多可变的参数。 { int count=0,i=first,sum=0; va_list maker; //va_list 类型数据可以保存函数的所有参数,做为一个列表一样保存。Va_list即是char*表明maker是一个字符型的指针。 va_start(maker,first); //设置列表的起始位置 **frist只是和maker在一起做参数,这并不说明maker指向frist而是指向first之后的第一个可变的参数,而frist是作为一个固定参数,因为它在…之前。这时候frist指向3。 while(i!=-1) { sum+=i; count++; i=va_arg(maker,int);//返回maker列表的当前值,并指向列表的下
Generic SBCS UNICODE TCHAR char wchar_t _TEOF EOF WEOF _TINT int wint_t _TSCHAR signed char wchar_t _TUCHAR unsigned char wchar_t _TXCHAR char wchar_t __T(x) x L __targv __argv __wargv __tcserror _strerror __wcserror __tcserror_s _strerror_s __wcserror_s _cgetts _cgets _cgetws _cgetts_s _cgets_s _cgetws_s _cputts _cputs _cputws _fgettc fgetc fgetwc _fgettc_nolock _fgetc_nolock _fgetwc_nolock _fgettchar _fgetchar _fgetwchar _fgetts fgets fgetws _fputtc fputc fputwc _fputtc_nolock _fputc_nolock _fputwc_nolock _fputtchar _fputchar _fputwchar _fputts fputs fputws _ftprintf fprintf fwprintf _ftprintf_l _fprintf_l _fwprintf_l _ftprintf_p _fprintf_p _fwprintf_p _ftprintf_p_l _fprintf_p_l _fwprintf_p_l _ftprintf_s fprintf_s fwprintf_s _ftprintf_s_l _fprintf_s_l _fwprintf_s_l _ftscanf fscanf fwscanf _ftscanf_l _fscanf_l _fwscanf_l _ftscanf_s fscanf_s fwscanf_s _ftscanf_s_l _fscanf_s_l _fwscanf_s_l _get_tpgmptr _get_pgmptr _get_wpgmptr _gettc getc getwc _gettc_nolock _getc_nolock _getwc_nolock _gettch _getch _getwch _gettch_nolock _getch_nolock _getwch_nolock _gettchar getchar getwchar _gettchar_nolock _getchar_nolock _getwchar_nolock _gettche _getche _getwche _gettche_nolock _getche_nolock _getwche_nolock _getts gets _getws _getts_s gets_s _getws_s _i64tot _i64toa _i64tow _i64tot_s _i64toa_s _i64tow_s _istalnum isalnum iswalnum _istalnum_l _isalnum_l _iswalnum_l _istalpha isalpha iswalpha _istalpha_l _isalpha_l _iswalpha_l _istascii __isascii iswascii _istcntrl iscntrl iswcntrl _istcntrl_l _iscntrl_l _iswcntrl_l _istdigit isdigit iswdigit _istdigit_l _isdigit_l _iswdigit_l _istgraph isgraph iswgraph _istgraph_l _isgraph_l _iswgraph_l _istlower islower iswlower _istlower_l _islower_l _iswlower_l _istprint isprint iswprint _istprint_l _isprint_l _iswprint_l _istpunct ispunct iswpunct _istpunct_l _ispunct_l _iswpunct_l _istspace isspace isw
telnet.c #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h> #include <unistd.h> #include <errno.h> #include <signal.h> #include <time.h> #include <stdarg.h> #define ERR_EXIT(
常见的string实现方式有两种,一种是深拷贝的方式,一种是COW(copy on write)写时拷贝方式,以前多数使用COW方式,但由于目前多线程使用越来越多,COW技术在多线程中会有额外的性能恶化,所以现在多数使用深拷贝的方式,但了解COW的技术实现还是很有必要的。
Signal是一种处理异常或异步改变执行流程的机制,类似于软中断。与POSIX兼容,VxWorks也定义了63种Signal(0为NULL Signal)
在Linux Server上不好模拟出来:不过若是先malloc,再越界memset,再free此内存块,然后malloc新内存块就会出现类似错误。
Log(DEBUG,"this is debug\n"); Log(INFO,"this is info\n"); Log(ERROR,"this is error\n"); Log(WARN,"this is warn\n");
对MySQL源码感兴趣的小伙伴,在学习源码的过程中都会有想一探某处代码在运行时当前的数据是个怎样的内容或者执行流程,想要知道具体情况无非可以通过两种方式,一种是gdb下断点查看,另外一种就是直接在想要查看的代码位置加入日志输出方式。输出日志的方式又分多种,比如有的可以用自带的设置调试模式输出调试日志,有的则可以采用自己添加输出错误日志形式。我们此处要说的就是使用后者,因本人比较习惯使用直接按自定义的格式自由组合输出且无参数限制方式,并希望实时看到输出信息,而目前现有的MySQL几个日志输出函数并不完全满足需求,因此在MySQL原有的一些函数基础上封装出一个可以满足需要的函数my_message_print。
FinSH 是 RT-Thread 的命令行组件,提供一套供用户在命令行调用的操作接口,主要用于调试或查看系统信息。它可以使用串口 / 以太网 / USB 等与 PC 机进行通信。 用户在控制终端输入命令,控制终端通过串口、USB、网络等方式将命令传给设备里的 FinSH,FinSH 会读取设备输入命令,解析并自动扫描内部函数表,寻找对应函数名,执行函数后输出回应,回应通过原路返回,将结果显示在控制终端上。 当使用串口连接设备与控制终端时,FinSH 命令的执行流程,如下图所示:
#include文件的目的就是把多个编译单元(也就是c或者cpp文件)公用的内容,单独放在一个文件里减少整体代码尺寸;或者提供跨工程公共代码。
1月17日,CNVD公开了D-LinkDIR 615/645/815 service.cgi远程命令执行漏洞(CNVD-2018-01084),freebuf上有前辈写了一篇漏洞复现和poc的文章(http://www.freebuf.com/new/160716.html)。 在上一篇文章(http://www.freebuf.com/vuls/160040.html)里实际操作了一下用qemu system模式模拟路由器环境,那这一次再通过分析CNVD-2018-01084实际操作一下用qemu use
等级:【要求】 说明:每个函数的代码行数控制应该控制在80行以内。如果超过这个限制函数内部逻辑一般可以拆分。如果试图超过这个标准,请列出理由。但理由不包含如下:
格式化函数是一类特殊的 ANSI C 函数,接受可变数量的参数,其中的一个就是所谓的格式化字符串。当函数求解格式化字符串时,它会访问向函数提供的额外参数。它是一个转换函数,用于将原始的 C 数据类型表示为人类可读的字符串形式。它们在几乎任何 C 程序中都会使用,来输出信息、打印错误信息或处理字符串。
格式化字符串函数可以接受可变数量的参数,并将第一个参数作为格式化字符串,根根据它来解析后面的参数。简单来说格式化字符串的漏洞就是格式字符串要求的参数和实际提供的参数不匹配。
互斥信号量的主要作用是对资源实现互斥访问,使用二值信号量也可以实现互斥访问的功能,不过互斥信号量与二值信号量有区别。下面我们先举一个通过二值信号量实现资源独享,即互斥访问的例子,让大家有一个形象的认识,进而引出要讲解的互斥信号量。
可以考虑使用char*fgets(char *dest ,int n, stdin);
接口请浏览:https://github.com/eyjian/mooon/blob/master/mooon/include/mooon/sys/log.h 实现头文件请浏览:https://github.com/eyjian/mooon/blob/master/mooon/include/mooon/sys/safe_logger.h 测试代码:https://github.com/eyjian/mooon/blob/master/mooon/test/sys/test_safe_logger.cpp 使用示例: MYLOG_DEBUG("[%d]MMMMM", 2015); 支持自动添加换行符,默认会自动添加换行符,但可以禁止自动添加换行符。还支持自动在行尾添加点号等功能。 下面是实现:
在《腾讯太极机器学习平台|Light在广告粗排中的数据下载与解析优化》一文里,我们介绍了在广告粗排场景中业务模型的特点,与我们在数据下载和解析方面所做的部分优化。
在学习C语言函数章节时发现,给函数传入的形参必须和函数定义原型的类型、数量一致才可以正常调用。
VC6编译方法: 1.http://www.openssl.org/source/old/0.9.x/ 下载0.9.x版本 -- VC6不能完全编译最新的1.0.x,所以尽量选择0.9.x 2.安装ActivePerl 3.cmd命令运行 VC6安装目录\VC98\Bin\VCVARS32.BAT 4.以此执行下面命令
输入和输出操作也可以在C++实现,通过使用C标准输入和输出库(cstdio,在C语言中称为stdio.h)。
最近在学习RT-Thread的使用,同时也相当于在拿它评估做产品的软件开发周期,最终学习的目的也就是希望能在未来的项目上用起来,STM32CubeMX其实已经支持了RT-Thread Nano的配置了,但我还是希望手动移植一下,没想到移植RT-Thread Nano如此简单,必须分享出来,哈哈哈!
一、服务器端日志与客户端日志的区别 在正式讲解之前,我们先来看一个日志类的实现方法,这个日志类也是代表着大多数客户端日志的主流写法: /** *@desc: 程序运行log类,log.h *@author: zhangyl *@date: 2017.01.17 **/ #ifndef __LOG_H__ #define __LOG_H__ #ifdef _ZYL_LOG_ #define LogInfo(...) Log::GetInstance(
程序的生命周期从一个高级C语言程序开始,这种形式能够被人读懂,却不能被机器读懂,为了在系统上运行这个程序,该源程序需要被其他程序转化为一系列低级机器语言指令,然后将这些指令按照可执行目标程序的格式打包并以二进制磁盘文件形式存储起来。 在Linux系统下,可用以下指令完成源程序到目标程序的转化:
领取专属 10元无门槛券
手把手带您无忧上云