1.什么意思c语言程序编程 undefined reference to ?
2.latexreference标题如何调整?
3.å¦ä½ç解@Resourceå@Referenceçåºå«
4.怎样才能在写代码时考虑到尽多的可能?
5.正点原子lwIP学习笔记——网络数据包管理
什么意思c语言程序编程 undefined reference to ?
最近在Linux下编程发现一个诡异的现象,就是在链接一个静态库的时候总是报错,类似下面这样的错误:
(。text+0x): undefined reference to `func'
关于undefined reference这样的问题,大家其实经常会遇到,在此,tkMapper源码我以详细地示例给出常见错误的各种原因以及解决方法,希望对初学者有所帮助。
1。 链接时缺失了相关目标文件(。o)
测试代码如下:
然后编译。
gcc -c test。c
gcc –c main。c
得到两个 。o 文件,一个是 main。o,一个是 test。o ,然后我们链接 。
o 得到可执行程序:
gcc -o main main。o
这时,你会发现,报错了:
main。o: In function `main':
main。c:(。text+0x7): undefined reference to `test'
collect2: ld returned 1 exit status
这就是最典型的undefined reference错误,因为在链接时发现找不到某个函数的实现文件,本例中test。
o文件中包含了test()函数的实现,所以如果按下面这种方式链接就没事了。
gcc -o main main。mybatis源码执行过程o test。o
扩展:其实上面为了让大家更加清楚底层原因,我把编译链接分开了,下面这样编译也会报undefined reference错,其实底层原因与上面是一样的。
gcc -o main main。c //缺少test()的实现文件
需要改成如下形式才能成功,将test()函数的实现文件一起编译。
gcc -o main main。c test。c //ok,没问题了
2。 链接时缺少相关的库文件(。
a/。so)
在此,只举个静态库的例子,假设源码如下。
先把test。c编译成静态库(。a)文件
gcc -c test。c
ar -rc test。a test。o
至此,我们得到了test。a文件。我们开始编译main。
c
gcc -c main。c
这时,则生成了main。o文件,然后我们再通过如下命令进行链接希望得到可执行程序。
gcc -o main main。源码安装rabbitmq集群o
你会发现,编译器报错了:
/tmp/ccCPAl。o: In function `main':
main。
c:(。text+0x7): undefined reference to `test'
collect2: ld returned 1 exit status
其根本原因也是找不到test()函数的实现文件,由于该test()函数的实现在test。
a这个静态库中的,故在链接的时候需要在其后加入test。a这个库,链接命令修改为如下形式即可。
gcc -o main main。o 。/test。a //注:。/ 是给出了test。a的路径
扩展:同样,为了把问题说清楚,上面我们把代码的编译链接分开了,如果希望一次性生成可执行程序,则可以对main。
c和test。a执行如下命令。
gcc -o main main。c 。/test。a //同样,如果不加test。a也会报错
3。 链接的库文件中又使用了另一个库文件
这种问题比较隐蔽,也是我最近遇到的与网上大家讨论的不同的问题,举例说明如下,免签约系统源码首先,还是看看测试代码。
从上图可以看出,main。c调用了test。c的函数,test。c中又调用了fun。c的函数。
首先,我们先对fun。c,test。c,main。c进行编译,生成 。o文件。
gcc -c func。c
gcc -c test。
c
gcc -c main。c
然后,将test。c和func。c各自打包成为静态库文件。
ar –rc func。a func。o
ar –rc test。a test。o
这时,我们准备将main。源码书面授权o链接为可执行程序,由于我们的main。
c中包含了对test()的调用,因此,应该在链接时将test。a作为我们的库文件,链接命令如下。
gcc -o main main。o test。a
这时,编译器仍然会报错,如下:
test。a(test。o): In function `test':
test。
c:(。text+0x): undefined reference to `func'
collect2: ld returned 1 exit status
就是说,链接的时候,发现我们的test。a调用了func()函数,找不到对应的实现。
由此我们发现,原来我们还需要将test。a所引用到的库文件也加进来才能成功链接,因此命令如下。
gcc -o main main。o test。a func。a
ok,这样就可以成功得到最终的程序了。同样,如果我们的库或者程序中引用了第三方库(如pthread。
a)则同样在链接的时候需要给出第三方库的路径和库文件,否则就会得到undefined reference的错误。
latexreference标题如何调整?
为了调整 LaTeX 文档中的参考文献标题,首先需要明确你使用的文档类。本文档主要针对使用 IEEEtran 的用户。通常,调整参考文献标题格式,需要修改 \refname 的定义方式和 \section 宏命令的格式。在下载源码并查找 \refname(大约在第 行)定义后,可发现其仅首字母大写。通过查找使用 \refname 的具体位置(约第 - 行),可以确认 Reference 部分采用 \section 定义。进一步探索 \section 的格式定义(大约第 - 行),会发现居中与小型大写字母(smallcaps)格式由 \centering\scshape 设置。由于 \def 定义通常不检查宏是否已存在,直接覆盖定义即可。使用 \begingroup 命令限制修改范围至参考文献表内,而 \makeatletter 启用内部函数处理 AT 字符。修改后,参考文献标题应显示为罗马体,以符合标准格式。
值得注意的是,使用模板时无需直接修改固定字符格式,若发现问题,建议联系模板维护者进行源头修正。此外,MWE(Minimal working example)应包含完整的可编译示例,以准确评估问题。
对于使用 biblatex 处理参考文献的用户,可以通过 \defbibheading 命令修改参考文献部分的 heading 格式,具体操作请参考 biblatex 手册。若在当前 group 内修改节标题格式,则需在补充描述后进行详细说明。
å¦ä½ç解@Resourceå@Referenceçåºå«
1ï¼å®ä¹ï¼
@Resourceï¼springç注解ï¼ä½ç¨ï¼springä¸è·åå·²ç»æ³¨å ¥å°springä¸çBean
@Reference: dubboç注解ï¼ä½ç¨ï¼æ³¨å ¥dubooæå¡ç对象
2ï¼éå°é®é¢ï¼
æ¬å°é ç½®ï¼
æ¥éï¼No provider available from registry **** for service ------------
åï¼ç»å ¸æ¥éï¼ä¸çé误就以为æ¯ç产è 没æå¯å¨å½ï¼å»zkä¸é¢çdubboç产è æ åµï¼çç没æï¼é®é¢å¥½åå·²ç»æ¾å°äºï¼ï¼ççï¼å¿½ç¶åç°ä»ä¸ºä»ä¹å»çæ¯ registry 1å¢ï¼ä¸åºè¯¥å»1å2é½æ¾åï¼ å¯¹äºï¼@Reference 注ådubboä¸ç®¡æ¯ä»ä¹æ¹å¼ï¼æ éæ¯registry å versionçæå®ï¼ç±äºæ没ææå®ï¼é£æç §springçç解è¯å®æ¯èµ°èªå¨è£ é å½ï¼é£æè¿è¾¹é ç½®äºä¸¤ä¸ªæ³¨åä¸å¿ï¼æ¯ä¸æ¯ä»ä¼æºè½çé½æ¾æ¾å¢ï¼ï¼ä¸æ¯çï¼dubboç产è å¦ææå®å¤ä¸ªregistryï¼ç¶å<dubbo:service/>声æçæå¡ä¼æ³¨åå°å¤ä¸ªæ³¨åä¸å¿ï¼<dubbo:reference/>æ¶è´¹ç«¯å¤æ³¨åä¸å¿æ¶æ¯éè¦æå®å»åªä¸ªæ³¨åä¸å¿çï¼æä¸æ³å¨@Referenceåé¢åä¸å¤§å ï¼å°±æ³èµ°èªå¨åè£ é ï¼æåæ¾å°å¯ä»¥å¨registry声ææ¶ default çå±æ§çï¼
æ ¹æ®ä¸ç³»åççæµãææé ç½®æ¹ä¸ºäºï¼
èªæ¤é®é¢è§£å³äºï¼ï¼ï¼ï¼ï¼
æåç°æ°çé®é¢ï¼ä½¿ç¨@Referenceæ¥æ³¨å ¥dubboæå¡ï¼é£å¦ææ项ç®ä¸å¤ä¸ªå°æ¹æ³ä½¿ç¨ï¼æå¨å¤ä¸ªç±»ä¸ä½¿ç¨@Reference ï¼å²ä¸æ¯æ³¨å ¥å¤ä¸ªbeanäºï¼è¿ä¸ªç解æ¯æé®é¢çï¼è¿æ¶æªæè¯å°ï¼ãè¿æ¾ç¶æ¯æé®é¢çï¼å æ¤ææ³å°dubboæå¡ä»¥åä¾æ³¨å ¥å°springä¸ï¼æ¢æ springèªå·±ç@Resourceæ ç¾æ¥è·åï¼å æ¤æå°é ç½®æ¹æäºä¸ä¸ï¼
æµè¯ä¸ä¸ï¼ç¡®å®å¥½ä½¿ï¼ï¼èªæ¤é 置使ç¨æ¹é¢æ²¡ä»ä¹é®é¢äºï¼ç¬¦åä¸ä¸ªäººçæ£å¸¸é»è¾äºï¼
ä½æ¯è¿æä¸ä¸ªé®é¢ï¼å°±æ¯ï¼
âæåç°æ°çé®é¢ï¼ä½¿ç¨@Referenceæ¥æ³¨å ¥dubboæå¡ï¼é£å¦ææ项ç®ä¸å¤ä¸ªå°æ¹æ³ä½¿ç¨ï¼æå¨å¤ä¸ªç±»ä¸ä½¿ç¨@Reference ï¼å²ä¸æ¯æ³¨å ¥å¤ä¸ªbeanäº â è¿ä¸ªé®é¢ççåå¨åï¼
ä¸é¢æ¥è§£çè¿ä¸ªé®é¢ï¼
springçé ç½® ä½¿ç¨ xml æè 注解 åªæ¯ 使ç¨æ¹å¼çä¸åï¼@Reference å <dubbo:reference/> çææåºè¯¥æ¯æ¯ä¸æ ·ç, springé»è®¤æ³¨å ¥Bean,scopeåºè¯¥æ¯singleton , é£æå¨å¤ä¸ªç±»ä¸ä½¿ç¨@Reference æ³¨å ¥åä¸ä¸ªdubboæå¡åºè¯¥æ¯å¨springä¸åªåå¨ä¸ä¸ªäºï¼ï¼äºå®ä¸çæ¯çï¼
å¤ä¸ª@Reference æ ç¾ æ³¨å ¥é 置信æ¯å®å ¨ç¸åç æå¡ ï¼æ¯ä¼ææå¡Beanç¼åçï¼ä¿è¯åªä¼æä¸ä¸ª æå¡Bean ,æºç å¦ä¸ï¼ è¿ä¸ªæ¹æ³ generateReferenceBeanCacheKey æ¯ç¼åkeyçè·åãã
private ReferenceBean<?> buildReferenceBean(Reference reference, Class<?> referenceClass) throws Exception { // è·åæå¡å¼ç¨å¯¹è±¡çç¼åkey String referenceBeanCacheKey = generateReferenceBeanCacheKey(reference, referenceClass); // ä»ç¼åmapä¸è·åæå¡å¼ç¨å¯¹è±¡ ReferenceBean<?> referenceBean = referenceBeansCache.get(referenceBeanCacheKey); if (referenceBean == null) { // å¦æå¼ç¨å¯¹è±¡ä¸ºç©ºï¼åéè¦å½åºå建ä¸ä¸ª ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder .create(reference, classLoader, applicationContext) .interfaceClass(referenceClass); referenceBean = beanBuilder.build(); //并ä¸æ¾å ¥å°ç¼åmapä¸ã referenceBeansCache.putIfAbsent(referenceBeanCacheKey, referenceBean); } return referenceBean; } private String generateReferenceBeanCacheKey(Reference reference, Class<?> beanClass) { // è·åæ¥å£å称 String interfaceName = resolveInterfaceName(reference, beanClass); // éè¿å¼ç¨çURl+æ¥å£å+æ¥å£çæ¬å·+æ¥å£åç»ï¼ç¨æ¥åç¼åkey String key = reference.url() + "/" + interfaceName + "/" + reference.version() + "/" + reference.group(); Environment environment = applicationContext.getEnvironment(); key = environment.resolvePlaceholders(key); return key; }
èªæ¤é®é¢è¯´æå®æ¯ãã
é®é¢æ´çï¼
1ï¼å¤æ³¨åä¸å¿æ¶ï¼spring èªå¨åè£ é æ¶ï¼éè¦èªå·±æå® æä¸ä¸ªæ³¨åä¸å¿ æè å°æ个注åä¸å¿ default设置为true.
2, @Resource å @Reference é½å¯ æ³¨å ¥ dubboæå¡ä½æ¯ æ¦å¿µæ¯ä¸ä¸æ ·çã
3ï¼@Reference 注解å¯ä»¥å¨å¤ä¸ªç±»ä¸æ³¨å ¥ ç¸åæå¡Bean ä¸ä¼é ææå¡Bean åå¨å¤ä¸ªãã
注ï¼æºç åè æç« /article/
怎样才能在写代码时考虑到尽多的可能?
对于如何在写代码的时候考虑到更多,第一部要做到“抄”。文雅地说,叫借鉴与模仿,把书上的基本习题抄一遍,去抄点源码。你不抄怎么知道编程语言的语法结构?你不抄怎么知道汉诺塔问题的递归实现?你不抄怎么知道怎样简洁把链表插入删除节点?第二步是默写。把你抄的默写下来,因为抄了不一定记住,背过了也会忘,当你闭着眼睛都能默打出来,你已经对这个问题有了认知。
第三步是理解。对于一个问题,当你默写了很多次以后你就会产生一个疑问,为啥这个是对的,还有没有更简单点的方法。例如哈夫曼树,你可以尝试去证明它的合理性。
第四步是应用。各大平台上肯定有不少练习,尝试用以学过的知识解答,举一反三,说白了就是理论学完了,该刷题了。当然我们无法把一种语言抽离出来,这时候做点项目什么的有利于加深对软件开发的认知和对语言的宏观理解。
第五步是拓展。当你刷够了很多题,你对这个问题的理解已经趋于完善。当你站着巨人的肩膀上,你要尝试看到更远的风景,比如尝试用更低的时间复杂度实现某一种算法。这时候你会发现以前抄的好的代码或者来源reference源码多么elegant。
最后,要巩固理论知识。当你参与到复杂的项目的时候,你会发现光靠那点破语法是远远不够的。当你写带网络通信的程序,需要学习计算机网络。当你发现你的代码无比繁冗且低效的时候,需要学习数据结构与算法。当你写编译器的时候,需要了解编译原理。当你写操作系统的时候,需要学习操作系统原理。
正点原子lwIP学习笔记——网络数据包管理
TCP/IP作为一种数据通信机制,其协议栈的实现本质上是对数据包的处理。为了实现高效率的处理,lwIP数据包管理提供了一种高效的机制。协议栈各层能够灵活处理数据包,同时减少数据在各层间传递时的时间和空间开销,这是提高协议栈工作效率的关键。在lwIP中,这种机制被称为pbuf。
用户的数据经过申请pbuf,拷贝到pbuf结构的内存堆中。在应用层,数据的前面加上应用层首部,在传输层加上传输层首部,最后在网络层加上网络层首部。
pbuf用于lwIP各层间数据传递,避免各层拷贝数据!
lwIP与标准TCP/IP协议栈的区别在于,lwIP是一种模糊分层的TCP/IP协议,大大提高了数据传输效率!
这是定义在pbuf.h中的关键结构体pbuf。通过指针next构建出了一个数据包的单向链表;payload指向的是现在这个结构体所存储的数据区域;tot_len是所有的数据长度,包括当前pbuf和后续所有pbuf;而len就是指当前pbuf的长度;type_internal有四种类型;ref代表当前pbuf被引用的次数。
右边展示的pbuf_layer就是用来首部地址偏移,用来对应相应的结构体。
PBUF_RAM采用内存堆,长度不定,一般用在传输数据;PBUF_POOL采用内存池,固定大小的内存块,所以分配速度快(一般字节,就是分配3个PBUF_POOL的内存池),一般用在中断服务中;PBUF_ROM和PBUF_REF都是内存池形式,而且只有pbuf没有数据区域,数据都是直接指向了内存区(PBUF_ROM指向ROM中,PBUF_REF指向RAM中)。
左边第一幅对应PBUF_RAM;中间两幅对应PBUF_POOL;最后一幅对应PBUF_ROM和PBUF_REF。
其中PBUF_RAM和PBUF_POOL相对更为常用。
更多的函数,都可以在pbuf.c和.h中找到。pbuf_alloc()如果是PBUF_REF或者是PBUF_ROM,就会如上图所示,创建一个结构体指针p,然后会进入pbuf_alloc_reference;该函数中,会申请一个pbuf结构体大小的内存;然后调用pbuf_init_alloced_pbuf进行初始化,初始化可以如上图所示。
如果是PBUF_POOL,会定义q和last两个pbuf结构体指针,q和last都初始化为NULL,rem_len(剩余长度)初始化为(用户指定需要构建的长度);然后q会经过内存申请,qlen则是去rem_len和当前可申请的数据大小(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset))取小值,然后同样经过pbuf_init_alloced_pbuf初始化q中的pbuf结构体;然后会把offset清零,就是说之后的pbuf都没有offset了,只有第一个链表的元素有offset;经过if判断并判断rem_len的大小,只要还有剩余就会回去循环继续执行上述操作,直到完成3个内存块的初始化。
首先会计算payload_len和alloc_len,如果是传输数据,那么LWIP_MEM_ALIGN_SIZE(offset)就是,计算得到payload_len=,alloc_len=;然后进入判断payload和alloc的长度是否
进入判断p是否为空,不为空证明还没有释放;进入while语句,每一次都--ref(引用次数);然后类似链表删除,调用相应的pbuf类型的内存释放(内存堆或者内存池),直到p全部被释放。源码如下:
这个就要看你使用的是什么类型,然后会根据类型来决定payload_len的大小,进行相应的payload指针指向数据区前的首部字段。
这一章主要讲述了lwIP中重要的pbuf缓冲,具体有哪些数据构成,为之后的学习奠定基础,确定了pbuf除了所需传输的数据,还有哪些变量需要添加,如何申请对应的pbuf内存大小,以及对应的内存堆和内存池。