顶烁科技招聘销售人员、渠道经理

0

公司介绍

公司正式成立于2013年1月,公司位于深圳市南山区蛇口半岛,环境幽美,交通便利,以帮助企业提升互联网品牌兑现能力为目标。我们的成员来自腾讯、深信服等优秀公司,有着自由的技术氛围和宽松的工作环境,经过一年多的前期耕耘,我们已经建立了产品和渠道资源,开始进入快速扩张时期。如果您与我们一样坚信技术改变生活;有着不竭的创造力和不达目的不罢休的折腾劲;内心渴望成就一段自己的事业;期望垂暮之时,安详的躺在摇椅上,跟小孙女讲述当年创业的故事…那么,我们是你苦苦追寻的一路人,赶紧加入我们吧!

 

职位信息

目前正处于快速发展期,您将有机会在快速的自我成长后,成为公司的业务核心人员、获得期权激励和业务分红。

作为渠道经理,您将有机会游历国内大好山水,在公司技术及后援支持下,接触全国各地的业务伙伴,您的主要职责大致如下:

1、制定、执行代理商开发方案,同时完成后续的扶持、管理。

2、完善渠道政策、渠道培训文档。

3、培训代理商产品知识、市场经验,提升代理商的业务能力。

4、举办会议和其它活动支持维系渠道关系。

 

作为销售人员,您将在公司技术及后援支持下与我们最直接的客户接触,获得最直接的业务经验和丰富的提成奖励,您的主要职责大致如下:

1、利用现有资源,完成客户的开发、沟通、协调,建立稳定的客户资源。

2、在技术及后缓团队并肩,销售推广公司产品(企业微信产品)。

3、通过客户挖掘产品的需求和运营技巧,不断完善公司产品。

4、管理能力优秀的将提拔为管理人员,带领业务同事完成公司销售任务。

 

联系方式

公司网站:http://www.etopshine.com

地址:南山区创业路中兴工业城10栋2层8212

电话:0755-2642-7375

邮箱:hr@etopshine.com

微薄:http://weibo.com/etopshine

微信公众号:

顶烁科技二维码

生成浏览器当前URL二维码的简单方式

3

这两年手机使用频率是不是提高不少,偶尔还需要将PC访问的页面快速在手机上访问?比如正看一篇精彩的文章,马上要出门了。二维码是手机与数字世界的纽带,如果这时候能快速生成当前页面URL的二维码,拿手机扫一下,再简单不过的事了。所以这个问题就变成了如何快速生成当前网页URL的二维码了。一般来说,对于chrome或是firefox这类可扩展浏览器,找个插件就实现了。可惜IE还是主流,找到一个IE插件不是件容易的事。这里提供一种快速生成当前页面二维码的方法:利用收藏夹(chrome下面叫书签栏)可以执行JS的特性,来完成它。

接下来就是我们要做的事。

第一步:显示收藏夹(chrome下面叫书签栏)

第二步:按Ctrl+D增加生成二维码“书签”,取一个自己喜欢的名字。

1

第三步:修改新增的“书签”,将其打开的地址修改成下面的。

javascript:window.open(‘http://api.kuaipai.cn/qr?chs=350×350&chl=’+encodeURIComponent(location.href));//chs= 后面的 × 符号是英文字母 x,这里被wordpress自动转义了

2

 

第四步:已经完成了,就这么简单,现在就点击书签栏看下效果吧。

 

这个小东西是源自看汪曾祺散文时的一个想法,他的文章都是很好看的小故事,他本人应该是一个很和气的人,把所有故事,即使是最难日子里面的,都写得很温暖。推荐一下,http://www.saohua.com/shuku/Wangzengqi/

 

应博友 Star Brilliant 提的建议

1、chs= 后面的 × 符号是英文字母 x,这里被wordpress自动转义了

2、URL用encodeURIComponent进行转义处理,避免URL中可能存在的特殊符号。

JSON状态表

0

年前遇到一个json_decode处理Unicode编码的问题,问题描述见http://www.php.net/manual/en/function.json-decode.php

json_decode can not handle string like:\u0014,it will return null,and with the error
<?php json_last_error()=JSON_ERROR_CTRL_CHAR ?>
according ascii_class from json module, use the next codes to fix the bug:
<?php
$str = preg_replace_callback(‘/([\x{0000}-\x{0008}]|[\x{000b}-\x{000c}]|[\x{000E}-\x{001F}])/u’, function($sub_match){return’\u00′ . dechex(ord($sub_match[1]));},$str);
var_dump(json_decode($str));
?>

分析了下php下该函数的实现,用到了状态表。之前学习语法分析器设计时遇到过,但是一直没有看到实际的应用场景,实际写JS语法分析器的时候用的是容易理解的从左至右递归下降的方式,JS实现的解析器里面还有PEGJS。Mark下,供有闲暇学习。

/*
The state transition table takes the current state and the current symbol,
and returns either a new state or an action. An action is represented as a
negative number. A JSON text is accepted if at the end of the text the
state is OK and if the mode is MODE_DONE.

1-9 ABCDF etc
sp wh { } [ ] : , ” \ / + – . 0 19 a b c d e f l n r s t u | E |*/
/*start GO*/ {GO,GO,-6,__,-5,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
/*ok OK*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
/*object OB*/ {OB,OB,__,-9,__,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
/*key KE*/ {KE,KE,__,__,__,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
/*colon CO*/ {CO,CO,__,__,__,__,-2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
/*value VA*/ {VA,VA,-6,__,-5,__,__,__,ST,__,__,__,MI,__,ZE,IN,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__},
/*array AR*/ {AR,AR,-6,__,-5,-7,__,__,ST,__,__,__,MI,__,ZE,IN,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__},
/*string ST*/ {ST,__,ST,ST,ST,ST,ST,ST,-4,ES,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST},
/*escape ES*/ {__,__,__,__,__,__,__,__,ST,ST,ST,__,__,__,__,__,__,ST,__,__,__,ST,__,ST,ST,__,ST,U1,__,__,__},
/*u1 U1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U2,U2,U2,U2,U2,U2,U2,U2,__,__,__,__,__,__,U2,U2,__},
/*u2 U2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U3,U3,U3,U3,U3,U3,U3,U3,__,__,__,__,__,__,U3,U3,__},
/*u3 U3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U4,U4,U4,U4,U4,U4,U4,U4,__,__,__,__,__,__,U4,U4,__},
/*u4 U4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ST,ST,ST,ST,ST,ST,ST,ST,__,__,__,__,__,__,ST,ST,__},
/*minus MI*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ZE,IN,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
/*zero ZE*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,FR,__,__,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
/*int IN*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,FR,IN,IN,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
/*frac FR*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,FR,FR,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
/*e E1*/ {__,__,__,__,__,__,__,__,__,__,__,E2,E2,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
/*ex E2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
/*exp E3*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
/*tr T1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T2,__,__,__,__,__,__},
/*tru T2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T3,__,__,__},
/*true T3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__},
/*fa F1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F2,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
/*fal F2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F3,__,__,__,__,__,__,__,__},
/*fals F3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F4,__,__,__,__,__},
/*false F4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__},
/*nu N1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N2,__,__,__},
/*nul N2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N3,__,__,__,__,__,__,__,__},
/*null N3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__},
};

最后的预言

0

–方舟子

握紧我的手

让我的图腾烙在你的手上
请传递这一把火 直到
百年之后 我所有绝望的嘶叫凝固
而此刻回声不绝如带雨的风
从一颗龟裂的心上抚过
那美丽的伤口如 礼花般开放
为一个最后的节日之夜殉葬

啊 那些长跪不起的人们
一夜夜静等灵光催命的闪耀
为每一次的劫难欢呼和嚎叫吧
但是我早已降临
在空旷的祭坛上悠悠地独步
一步步踏碎绿树红墙守护的古老梦境
碎影依然伟大如魔鬼 然而不再长久
告诉你们吧 这一刻的阵痛
乃是不可告人的无上欢乐
我不死的种子 在城楼那双神秘的眼下
挣扎着播散如四溢的血
带血的宁馨儿
比水晶里的人神更为不朽

深圳的电动车

0

早上去会展中心,取了杨志亲大哥给大玲留下来的一箱鸡蛋。礼物不重,但是执意要打车送过来,盛情难却,又不想让对方太费神。于是山不过来,我便过去,让大玲找了个借口,说过去办公事,回来地铁顺道取一下。

在桃园地铁口,发现都有两个交警把守。桃园站临南山医院、南山消费区,这一带人流比较多。打车费用高、公交车不方便,电动车在是比较常见的接驳工具,无奈深圳限电之后,电动车成了过街老鼠。骑的人心惶惶,旁观的人冷眼无视。在又一场无声息的抗争之后,骑电动车的大多数人,没能说上话,就被开车的人定为违规了。

限电已经来了,禁电就不远了。除了几句抱怨,慢慢,人们便习惯电动车是违法交通工具的事实,忘记了97年之后深圳再未建非机动车道的事实。而一水之隔的对岸,香港人民的摩托车正潇洒的在两车道上飞驰,既不扰民,也没有被安上破坏环境,莫须有的罪名。果真应了那句话:

有什么样的人民,便有什么样的政府。

即刻启程

0

昨天到科创中心走完了离职的最后流程。2008.3.24怀揣着500块提着箱子开始实习。五年后忘了挥衣袖,带走了一床薄被,一个杯子。

加入时公司200人,离开时已经到1300多人,在金融基地前台墙上,已经很难再从容的挂上新的公司全家福。在我职业生涯的第五个年头,也是在Sangfor的第五个年头,我走下了这趟快速行驶的列车,踏上新的旅程。是离别就需要拿出勇气去告别旧的朋友、稳定的环境、还有一段旧的时光。也就必然有着反复而漫长的反省和思考,关于昨天、当下和未来。结果是在离职原因写上:

在踏入婚姻坟墓的之前,是时候作出一些改变,换另一种方式继续提升自己。磨剑五年,带着所学开始出去闯荡。

准备创业了!

winding-road

这不是一时热血的鲁莽。毕业当年,指点前程,信誓旦旦,大有不创伟业誓不还的气势,借用毛的诗:

孩儿立志出乡关,不取功名誓不还. 埋骨何须桑梓树,人生无处不青山.

毕业视频上放言,四十岁之前赚到一千万!如今看来虽有偏颇之处,但创业的念头疾风中之劲草,当时间越逼近当年计划的五年沉积之末时,愈发强烈。万事俱备之时难侯,韶华之期易逝。与其空等水到渠成,不如现在开始吧。
临别前,我作了一次尝试:

——一次机会
何老大:
2008.3.24进入深信服,如今已五载,是时候作一个总结。在发这封邮件之前,我已经提交了离职信,如离职原因所言,“在进入稳定的婚姻坟墓前,是时候作出一些改变,换另一种方式继续提升自己”。五年磨剑,我准备带着从深信服学到的东西开始出去闯荡。一般讲来,一个良好运转的普通员工离职不会起太多波澜,更不至于惊动到您,您将继续领导深信服前行,而我将面对真实的创业环境,野蛮生长。但过往的经历让我知道,努力尝试加上缘分,可能会产生意外。
我想做一次冒昧的尝试:请老板吃一次饭。饭是普通的饭,但将赤诚以对,知无不言,对我来说将是一次非凡的经历,希望对您也会有一些帮助。我愿意谈谈我自己和在深信服的这些年,谈谈对未来的看法。少数杰出的员工可以带领公司前行,这个群体是公司关注较多的。但多数像我这样普通的员工是公司前进的划桨者,公司虽偶有员工访谈,但我相信有一些肺腑之言还留在了心里。您也可以谈谈你自己,谈谈在深信服的这些年,谈谈作为一个创业者是如何成长起来的,这些将成为我人生中不可多得的指导经验,照耀我的奋斗之路。 这是一次机会。
您事务繁多,我能接受任何答复。不管如何,在此表达一位创业新手对一位老将的崇敬之情!

廖伟强
2013.4.28

当然得到的答复不出意料

——Re:一次机会
很抱歉没有及时回复你的邮件,也非常遗憾深信服无法为你提供进一步发展的机会。
同时也祝福你创业路上取得大的成就。每一个深信服的同事取得人生的成功(不管是不是在深信服取得的),都是令我感到骄傲的事情。

吃饭就免了,你可以随时来找我聊一聊,也可以书面和我沟通,我也愿意倾听你对深信服过去和未来的一些看法,包括分享一些自己的经历。

 

新的办公室已经租好,24平方丈之地将是另一场奋斗的起点,外包(www.etopshine.com)起步练手,即刻启程!

me

 

PHP REST框架开源项目prest

0

源代码托管地址:https://github.com/hellolwq/prest
作者:顶烁科技
特性描述:
本API目前测试的是Linux+Apache+Mysql+PHP环境,其它环境暂时没有测试。
1、api与类方法一一对应,方便快速添加。
2、支持api类方法参数检查。
3、支持权限检查。
4、支持ticket生成、校验,可防止被中间人盗用。
5、支持API自定义缓存时间。
6、继承restdb可使用默认数据库方法。

一、配置Apache支持.htaccess文件

AllowOverride All
Options FollowSymLinks

二、配置rest/inc/config.php

三、使用rest.sql建立数据库
1、登录帐号http://host/rest/user/login?uname=test&passwd=test
2、测试其它接口http://host/rest/user/add?uname=test&passwd=test

四、添加接口
在rest/handlers目录添加对应类文件和静态方法即可。
比如,需要添加http://host/rest/foo/test?arg1=xxx&arg2=xxx&xxx接口。
参数目前可以通过querystring或是post方式传入。
添加foo.php文件

class foo{
public function test($arg1,$arg2...)
{
auth::check_permission(ROLE_ADMIN);/*检查该方法要求的权限*/
#logic about $obj
....
return new response(array('body'=>$obj,’cache’=>’5′));
}
}
目前返回对象支持:
body:返回正文对象,可以是任何的变量,将转换成json格式返回。
cache:缓存秒数,默认为无缓存。
header:自定义头部对象,里面是key=>value对的数组。
code:返回的http状态码。
五、自定义路径映射
修改config.php变量,加入映射关系。
$g_maps = array(
…,
‘/abc/test’=>array(
‘class’=>’foo’,
‘method’=>’test’
)
)

TODO LIST
1、按http规范,对有副作用影响接口强制要求使用POST/DELETE/PUT 等方法。
2、补充功能函数,目前只添加了对mysql数据库的基本操作。

一道正则表达式题

0

Elance.com的PHP水平测试,其中有一个题目是这样的:

Write a function declared as function ReformatPhoneNumber($number), whose argument will contain string data representing some phone number data (entered by the user). A valid phone number may consist of

between 7 and 12 digits (0..9). Assume that in between some adjacent digits there may optionally appear either a single space, or a single hyphen (-). Any other phone number should be considered invalid.

If the phone number is valid, the return value of your function should contain a string containing between 7 and 12 digits, representing the same phone number after removing all hyphens and spaces. If the

phone number is invalid, throw a standard PHP5 Exception initialized with the text “Invalid phone number”.

The first and the last character of the string should be a number.

For example, after calling ReformatPhoneNumber(’012-345 69′) the return value should be ’01234569′. Calling the function with any of these values: ’012345′, ‘-012345 678′, ’01203- 34566′, ’123456678875432′,

’1234×567′ should result in an exception.

该题的关键部分是效验用户输入的电话号码是否合法,因可能因为有意或无意的原因,得到的结果可能是不正确的,不能信任用户、前端的任何输入。因此这里要根据下面的规则判断输入是否为合法的电话号码:

  1. 电话号码由7-12位数字组成,每位数据是0-9.
  2. 数字中间可以由-或是空格作分隔符,但是数字只间只能有一个分隔符号,不能出现a  b,a–b,a- b这种多个分隔符的情况。
  3. 开始和结尾只能是数字。

分享下解题思路:

  1. 因为这里的判断条件较多,直接使用字符操作可能较复杂,首选正则表达式。
  2. 字符串的规律是数字开始,后面-、空格和数字组合的重复,在正则表达式里面可以*,+,{a,b},?等限定。
  3. 为了避免有多个分隔符,要求分隔符后立即接数字,因此该组合应该是[- ]\d,事实上分隔符号不是必须的,因此修改为[- ]?\d。结合推理项2,在不考虑长度的情况下,即为^\d([- ]?\d)*,这个表达式有个。该正则表达式,正好还满足了结尾必定是数字。
  4. 最后,考虑电话号码数长度为7-12的情况,因为这个正则表达式是一个数字和数字、分隔符号组合重复(事实上该组合只包含一个数字),那么只要限制组合的个数就可以限定数字的总长度了。于是正则表达式的最终值为:^\d([- ]?\d){6,11}$
有了正则表达式,完整解也就呼之欲出了。

function ReformatPhoneNumber($phone)
{
if(!preg_match('/^\d([- ]?\d){6,11}$/', $phone))
throw new Exception('input valid!');
return preg_replace('/[ |-]/','',$phone);
}

echo ReformatPhoneNumber("1-234678");

老师托梦

0

online casinos

QEMU的HACKING文件

0

qemu工程根目录下的HACKING文件,不仅适用于修改开源项目,写所有程序的时候都应该保持同样的良好习惯。

1. Preprocessor

For variadic macros, stick with this C99-like syntax:

#define DPRINTF(fmt, …) \
do { printf(“IRQ: ” fmt, ## __VA_ARGS__); } while (0)

2. C types

It should be common sense to use the right type, but we have collected
a few useful guidelines here.

2.1. Scalars

If you’re using “int” or “long”, odds are good that there’s a better type.
If a variable is counting something, it should be declared with an
unsigned type.

If it’s host memory-size related, size_t should be a good choice (use
ssize_t only if required). Guest RAM memory offsets must use ram_addr_t,
but only for RAM, it may not cover whole guest address space.

If it’s file-size related, use off_t.
If it’s file-offset related (i.e., signed), use off_t.
If it’s just counting small numbers use “unsigned int”;
(on all but oddball embedded systems, you can assume that that
type is at least four bytes wide).

In the event that you require a specific width, use a standard type
like int32_t, uint32_t, uint64_t, etc. The specific types are
mandatory for VMState fields.

Don’t use Linux kernel internal types like u32, __u32 or __le32.

Use target_phys_addr_t for guest physical addresses except pcibus_t
for PCI addresses. In addition, ram_addr_t is a QEMU internal address
space that maps guest RAM physical addresses into an intermediate
address space that can map to host virtual address spaces. Generally
speaking, the size of guest memory can always fit into ram_addr_t but
it would not be correct to store an actual guest physical address in a
ram_addr_t.

Use target_ulong (or abi_ulong) for CPU virtual addresses, however
devices should not need to use target_ulong.

Of course, take all of the above with a grain of salt. If you’re about
to use some system interface that requires a type like size_t, pid_t or
off_t, use matching types for any corresponding variables.

Also, if you try to use e.g., “unsigned int” as a type, and that
conflicts with the signedness of a related variable, sometimes
it’s best just to use the *wrong* type, if “pulling the thread”
and fixing all related variables would be too invasive.

Finally, while using descriptive types is important, be careful not to
go overboard. If whatever you’re doing causes warnings, or requires
casts, then reconsider or ask for help.

2.2. Pointers

Ensure that all of your pointers are “const-correct”.
Unless a pointer is used to modify the pointed-to storage,
give it the “const” attribute. That way, the reader knows
up-front that this is a read-only pointer. Perhaps more
importantly, if we’re diligent about this, when you see a non-const
pointer, you’re guaranteed that it is used to modify the storage
it points to, or it is aliased to another pointer that is.

2.3. Typedefs
Typedefs are used to eliminate the redundant ‘struct’ keyword.

2.4. Reserved namespaces in C and POSIX
Underscore capital, double underscore, and underscore ‘t’ suffixes should be
avoided.

3. Low level memory management

Use of the malloc/free/realloc/calloc/valloc/memalign/posix_memalign
APIs is not allowed in the QEMU codebase. Instead of these routines,
use the GLib memory allocation routines g_malloc/g_malloc0/g_new/
g_new0/g_realloc/g_free or QEMU’s qemu_vmalloc/qemu_memalign/qemu_vfree
APIs.

Please note that g_malloc will exit on allocation failure, so there
is no need to test for failure (as you would have to with malloc).
Calling g_malloc with a zero size is valid and will return NULL.

Memory allocated by qemu_vmalloc or qemu_memalign must be freed with
qemu_vfree, since breaking this will cause problems on Win32 and user
emulators.

4. String manipulation

Do not use the strncpy function. According to the man page, it does
*not* guarantee a NULL-terminated buffer, which makes it extremely dangerous
to use. Instead, use functionally equivalent function:
void pstrcpy(char *buf, int buf_size, const char *str)

Don’t use strcat because it can’t check for buffer overflows, but:
char *pstrcat(char *buf, int buf_size, const char *s)

The same limitation exists with sprintf and vsprintf, so use snprintf and
vsnprintf.

QEMU provides other useful string functions:
int strstart(const char *str, const char *val, const char **ptr)
int stristart(const char *str, const char *val, const char **ptr)
int qemu_strnlen(const char *s, int max_len)

There are also replacement character processing macros for isxyz and toxyz,
so instead of e.g. isalnum you should use qemu_isalnum.

Because of the memory management rules, you must use g_strdup/g_strndup
instead of plain strdup/strndup.

5. Printf-style functions

Whenever you add a new printf-style function, i.e., one with a format
string argument and following “…” in its prototype, be sure to use
gcc’s printf attribute directive in the prototype.

This makes it so gcc’s -Wformat and -Wformat-security options can do
their jobs and cross-check format strings with the number and types
of arguments.

Go to Top