c 11 Variadic Printf性能
作者:互联网
可变参数模板在c 11中介绍.我发现printf函数可以使用它替换.
但是,cout用于实现.我想知道是否有可能使用其他东西来实现类型安全但不牺牲太多性能.
void safe_printf(const char *s)
{
while (*s) {
if (*s == '%') {
if (*(s + 1) == '%') {
++s;
}
else {
throw "invalid format string: missing arguments";
}
}
std::cout << *s++;
}
}
template<typename T, typename... Args>
void safe_printf(const char *s, T& value, Args... args)
{
while (*s) {
if (*s == '%') {
if (*(s + 1) == '%') {
++s;
}
else {
std::cout << value;
safe_printf(s + 1, args...); // call even when *s == 0 to detect extra arguments
return;
}
}
std::cout << *s++;
}
throw "extra arguments provided to printf";
}
编辑:确定作为请求,我执行测试来比较cout和printf之间的性能.
gcc版本4.8.1,x86_64-redhat-linux
#include <iostream>
#include <cstdio>
#include <ctime>
#include <string>
#include <stdint.h>
#include <sstream>
using namespace std;
int32_t val = 10;
string s = "avcccc";
void TestOne(){
for(int i = 0; i < 1000000; i++){
printf("This is the value: %d, %s\n", i, s.c_str());
}
}
void TestTwo(){
ios_base::sync_with_stdio(false);
for(int i = 0; i < 1000000; i++){
cout << "This is the value: " << i << ", " << s << "\n";
}
}
int main( int argc, char * argcv[] )
{
timespec start;
clock_gettime(CLOCK_REALTIME, &start);
TestOne();
timespec end;
clock_gettime(CLOCK_REALTIME, &end);
timespec start2;
clock_gettime(CLOCK_REALTIME, &start2);
TestTwo();
timespec end2;
clock_gettime(CLOCK_REALTIME, &end2);
int64_t d1 = ((end.tv_sec - start.tv_sec) * 1000000000) + (end.tv_nsec - start.tv_nsec);
int64_t d2 = ((end2.tv_sec - start2.tv_sec) * 1000000000) + (end2.tv_nsec - start2.tv_nsec);
cout << "printf:" << d1 << " cout:" << d2 << ", diff(prinf-cout) " << d1-d2 << endl;
}
没有关闭sync_with_stdio.
printf:242862382 cout:275197806, diff(prinf-cout) -32335424
printf:201481941 cout:226177849, diff(prinf-cout) -24695908
printf:244915215 cout:275071790, diff(prinf-cout) -30156575
printf:235603694 cout:286859058, diff(prinf-cout) -51255364
printf:230076992 cout:248738879, diff(prinf-cout) -18661887
printf:223023056 cout:246486805, diff(prinf-cout) -23463749
printf:229922272 cout:269340309, diff(prinf-cout) -39418037
printf:228955230 cout:270675387, diff(prinf-cout) -41720157
printf:228390291 cout:228521421, diff(prinf-cout) -131130
printf:248419954 cout:268399737, diff(prinf-cout) -19979783
printf:229476729 cout:254635928, diff(prinf-cout) -25159199
printf:229646751 cout:252797729, diff(prinf-cout) -23150978
printf:227093478 cout:255390754, diff(prinf-cout) -28297276
printf:199161604 cout:224850870, diff(prinf-cout) -25689266
printf:198763304 cout:225709890, diff(prinf-cout) -26946586
printf:200445025 cout:223221944, diff(prinf-cout) -22776919
printf:202760174 cout:232363225, diff(prinf-cout) -29603051
printf:201989909 cout:225384923, diff(prinf-cout) -23395014
printf:202773400 cout:221465068, diff(prinf-cout) -18691668
printf:199076506 cout:223602064, diff(prinf-cout) -24525558
printf:200153338 cout:228610432, diff(prinf-cout) -28457094
printf:202794950 cout:223272108, diff(prinf-cout) -20477158
printf:209928648 cout:232300225, diff(prinf-cout) -22371577
printf:209722611 cout:233044140, diff(prinf-cout) -23321529
printf:248807680 cout:264406580, diff(prinf-cout) -15598900
printf:242916731 cout:246345645, diff(prinf-cout) -3428914
printf:221375038 cout:252251979, diff(prinf-cout) -30876941
printf:232892684 cout:273617728, diff(prinf-cout) -40725044
printf:238734317 cout:294238303, diff(prinf-cout) -55503986
printf:243180284 cout:284243039, diff(prinf-cout) -41062755
printf:245863056 cout:270413734, diff(prinf-cout) -24550678
printf:229300100 cout:259492696, diff(prinf-cout) -30192596
printf:227563904 cout:247802177, diff(prinf-cout) -20238273
printf:206847682 cout:230084237, diff(prinf-cout) -23236555
printf:198457595 cout:227655859, diff(prinf-cout) -29198264
printf:200265832 cout:224559564, diff(prinf-cout) -24293732
printf:201723563 cout:221764167, diff(prinf-cout) -20040604
printf:203430800 cout:221937208, diff(prinf-cout) -18506408
printf:198619127 cout:222313750, diff(prinf-cout) -23694623
printf:197686981 cout:233131170, diff(prinf-cout) -35444189
printf:199909645 cout:222764002, diff(prinf-cout) -22854357
printf:198050669 cout:221853069, diff(prinf-cout) -23802400
printf:200002449 cout:222743999, diff(prinf-cout) -22741550
printf:198573481 cout:221842796, diff(prinf-cout) -23269315
printf:200349434 cout:221501830, diff(prinf-cout) -21152396
printf:202039344 cout:238001170, diff(prinf-cout) -35961826
printf:209269614 cout:223050036, diff(prinf-cout) -13780422
printf:202794419 cout:219673749, diff(prinf-cout) -16879330
printf:223558422 cout:248919110, diff(prinf-cout) -25360688
printf:204139028 cout:231116364, diff(prinf-cout) -26977336
关闭sync_with_stdio
printf:228312005 cout:203814832, diff(prinf-cout) 24497173
printf:197367087 cout:170933621, diff(prinf-cout) 26433466
printf:203728802 cout:177833838, diff(prinf-cout) 25894964
printf:205758316 cout:180175924, diff(prinf-cout) 25582392
printf:251267252 cout:218081227, diff(prinf-cout) 33186025
printf:232029455 cout:199609356, diff(prinf-cout) 32420099
printf:246392438 cout:217010908, diff(prinf-cout) 29381530
printf:241149944 cout:202337266, diff(prinf-cout) 38812678
printf:222466515 cout:195872690, diff(prinf-cout) 26593825
printf:221633699 cout:206460840, diff(prinf-cout) 15172859
printf:229958105 cout:200284936, diff(prinf-cout) 29673169
printf:227201946 cout:195657372, diff(prinf-cout) 31544574
printf:244297134 cout:219042472, diff(prinf-cout) 25254662
printf:251881002 cout:216385940, diff(prinf-cout) 35495062
printf:227101117 cout:205227849, diff(prinf-cout) 21873268
printf:203951925 cout:177981416, diff(prinf-cout) 25970509
printf:201715048 cout:178496585, diff(prinf-cout) 23218463
printf:197549273 cout:175482278, diff(prinf-cout) 22066995
printf:239984907 cout:203745670, diff(prinf-cout) 36239237
printf:205235507 cout:181894912, diff(prinf-cout) 23340595
printf:203233202 cout:178961277, diff(prinf-cout) 24271925
printf:206434353 cout:173567831, diff(prinf-cout) 32866522
printf:202660160 cout:176737473, diff(prinf-cout) 25922687
printf:201831315 cout:175735846, diff(prinf-cout) 26095469
printf:200164787 cout:175192017, diff(prinf-cout) 24972770
printf:202584304 cout:177037255, diff(prinf-cout) 25547049
printf:204783650 cout:177513872, diff(prinf-cout) 27269778
printf:241033670 cout:220023173, diff(prinf-cout) 21010497
printf:247117709 cout:189569108, diff(prinf-cout) 57548601
printf:248105314 cout:219065335, diff(prinf-cout) 29039979
printf:236633133 cout:212964896, diff(prinf-cout) 23668237
printf:223496747 cout:195898087, diff(prinf-cout) 27598660
printf:224936154 cout:199397373, diff(prinf-cout) 25538781
printf:234572132 cout:216805022, diff(prinf-cout) 17767110
printf:246738504 cout:216305235, diff(prinf-cout) 30433269
printf:250904282 cout:217312285, diff(prinf-cout) 33591997
printf:208721377 cout:181195577, diff(prinf-cout) 27525800
printf:236245042 cout:203088785, diff(prinf-cout) 33156257
printf:204058026 cout:179401451, diff(prinf-cout) 24656575
printf:201038295 cout:176858089, diff(prinf-cout) 24180206
printf:204590031 cout:186586920, diff(prinf-cout) 18003111
printf:200774025 cout:177748984, diff(prinf-cout) 23025041
printf:203636203 cout:179084720, diff(prinf-cout) 24551483
printf:202479901 cout:179167171, diff(prinf-cout) 23312730
printf:202329892 cout:180674842, diff(prinf-cout) 21655050
printf:201305734 cout:179149029, diff(prinf-cout) 22156705
printf:200157089 cout:178860913, diff(prinf-cout) 21296176
printf:202803518 cout:177353141, diff(prinf-cout) 25450377
printf:204768180 cout:175608340, diff(prinf-cout) 29159840
printf:237805444 cout:205725465, diff(prinf-cout) 32079979
因此,如果关闭sync_with_stdio,我之前没有听过sync_with_stdio,那么cout可以输出性能printf.
我不知道关闭是否有副作用.
如上所述的variadic printf包含在测试中.
void TestThree(){
ios_base::sync_with_stdio(false);
for(int i = 0; i < 1000000; i++){
safe_printf("This is the value: %d, %s\n", i, s.c_str());
}
}
再次打印仍然更快,即使sync_with_stdio关闭,我不太明白.
printf:204099118 cout:684881656, diff(prinf-cout) -480782538
printf:227662054 cout:758110546, diff(prinf-cout) -530448492
printf:221534729 cout:732899502, diff(prinf-cout) -511364773
printf:203223553 cout:669386010, diff(prinf-cout) -466162457
printf:199923091 cout:662735504, diff(prinf-cout) -462812413
printf:207555026 cout:676522292, diff(prinf-cout) -468967266
printf:204846108 cout:655571171, diff(prinf-cout) -450725063
printf:199512948 cout:660717898, diff(prinf-cout) -461204950
printf:204251614 cout:676688426, diff(prinf-cout) -472436812
printf:201601655 cout:677217080, diff(prinf-cout) -475615425
printf:200311160 cout:674022044, diff(prinf-cout) -473710884
printf:202562272 cout:658126890, diff(prinf-cout) -455564618
printf:203100080 cout:660348312, diff(prinf-cout) -457248232
printf:228058969 cout:743305386, diff(prinf-cout) -515246417
printf:223976399 cout:742205352, diff(prinf-cout) -518228953
printf:204651603 cout:681893639, diff(prinf-cout) -477242036
printf:222386690 cout:745000014, diff(prinf-cout) -522613324
printf:217610811 cout:790129902, diff(prinf-cout) -572519091
printf:224156133 cout:758849874, diff(prinf-cout) -534693741
printf:204485998 cout:660430561, diff(prinf-cout) -455944563
printf:201259591 cout:667987480, diff(prinf-cout) -466727889
printf:204473955 cout:658096409, diff(prinf-cout) -453622454
printf:201986282 cout:670503647, diff(prinf-cout) -468517365
printf:204846379 cout:687089511, diff(prinf-cout) -482243132
printf:204962342 cout:681630774, diff(prinf-cout) -476668432
printf:202546744 cout:662300255, diff(prinf-cout) -459753511
printf:220856194 cout:757583221, diff(prinf-cout) -536727027
printf:232926622 cout:837024111, diff(prinf-cout) -604097489
printf:234187491 cout:801665699, diff(prinf-cout) -567478208
printf:244214945 cout:787558503, diff(prinf-cout) -543343558
printf:220227724 cout:788444837, diff(prinf-cout) -568217113
printf:227440252 cout:754596137, diff(prinf-cout) -527155885
printf:238158449 cout:814421312, diff(prinf-cout) -576262863
printf:205372147 cout:676782112, diff(prinf-cout) -471409965
printf:197566880 cout:662635516, diff(prinf-cout) -465068636
printf:199640024 cout:726088581, diff(prinf-cout) -526448557
printf:201249659 cout:660196078, diff(prinf-cout) -458946419
printf:201578923 cout:676444130, diff(prinf-cout) -474865207
printf:201034436 cout:690638993, diff(prinf-cout) -489604557
printf:208951246 cout:682032486, diff(prinf-cout) -473081240
printf:199928991 cout:673437083, diff(prinf-cout) -473508092
printf:233538795 cout:810890687, diff(prinf-cout) -577351892
printf:243872766 cout:847098807, diff(prinf-cout) -603226041
printf:243341748 cout:769877622, diff(prinf-cout) -526535874
printf:230232172 cout:733867319, diff(prinf-cout) -503635147
printf:220371109 cout:709704232, diff(prinf-cout) -489333123
printf:251803876 cout:790624221, diff(prinf-cout) -538820345
printf:202999188 cout:910149931, diff(prinf-cout) -707150743
printf:201931656 cout:669276274, diff(prinf-cout) -467344618
printf:200511370 cout:677748018, diff(prinf-cout) -477236648
解决方法:
Andrei Alexandrescu的safe_printf功能非常聪明,但不幸的是有严重的局限性:
>每个参数处理两次,一次检查其有效性,第二次用printf格式化.可以在释放模式下禁用该检查以避免开销,但这严重破坏了安全性.
>它不适用于位置参数.
您可以通过多种方式改进它:
>建立参数类型后,不要总是将格式转发到printf.例如,this benchmark表明可以实现整数格式化,这比sprintf快6.7倍.
>要实现位置参数,您需要将参数存储在数组中,因为它们需要通过索引进行寻址.
以下是如何完成的示例:
class Arg {
private:
enum Type { INT, DOUBLE };
Type type;
union {
int int_value;
double dbl_value;
} u;
public:
Arg(int value) : type(INT) { u.int_value = value; }
Arg(double value) : type(DOUBLE) { u.dbl_value = value; }
// other types
};
void do_safe_printf(const char *format, const Arg *args, size_t num_args) {
// here we can access arguments by index
}
template <typename... Args>
void safe_printf(const char *format, const Args&... args) {
Arg arg_array[] = {args...};
do_safe_printf(format, arg_array, sizeof...(Args));
}
除了支持位置参数之外,这种方法还将最小化代码膨胀,因为所有工作都由单个函数do_safe_printf完成,而safe_printf函数模板仅将参数放在数组中.
这些和其他改进已在fmt library中实施.根据基准测试,它在speed和compiled code size都与原生printf实现相当.
免责声明:我是这个图书馆的作者.
标签:c,c11,printf,formatting,variadic-functions 来源: https://codeday.me/bug/20190926/1822214.html