完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
您好。我把函数指针作为参数传递给函数时遇到了一些问题。问题基本上是在一些循环下,函数指针是空的。最后检查代码和注释(1):(1)这是关键。如果我不使用这个句子,“数据”指针总是空的。使用时,“数据”具有正确的函数地址。我猜想编译器正在做一些它的优化魔术,因为函数指针没有被使用,它简单地丢弃它,默认情况下,它对函数地址无效。我记得在论坛的某个地方读到过这件事,但是我失去了线索。如果我使用函数(指针一旦设置或直接调用原始函数)在任何地方(内部或外部的函数)地址是可以的,但如果我不使用它…问题。我尝试禁用优化,但结果是一样的,NULL。欢迎任何想法或建议。TY。
以上来自于百度翻译 以下为原文 Hello. I'm having some problems with passing function pointers as parameter to function. The problem is basically under some circunstances the pointer to function is NULL. Check the code and note (1) at the end: // function signature, quite simple typedef void (* function_p)(void); // just a simple function to check the function void f1(void) // @ 0xAACC { static int a = 0; a++; } // to manipulate the address (one of some tests) volatile union { function_p function; uint16_t addr; // I know they are so 16-bit address so, it's fine for the test } ufun; // gets a pointer to function (any) and simply fills the addr field in the union. // for the simplicity it uses the signature above void function_addr (const void * data) { ufun.addr = data; if (ufun.addr) { //ufun.function(); // (1) } } void main(void) { function_addr(f1); ufun.addr++; // just to mess while(1); } (1) This is the key. If I don't use this sentence, "data" pointer is always NULL. When used, "data" has the correct function address. I guess the compiler is doing some of its optimizing magic and since the function pointer is not being used it simply discards it and by default asigns NULL to the function address. I remember reading something about this in some place in the forum but I lost the thread. If I use the function (the pointer once it's set or just calling the original function directly) in any place (internal or externally to the function) the address is ok, but if I don't use it... problem. I tried disabling optimizations but the result is the same, NULL. Any idea or suggestion is welcome. Ty. |
|
相关推荐
16个回答
|
|
开始摆脱这个。将指针指向函数/从指针转换为空洞是不合法的。也使你的计数器处于F1()的易失性,这样编译器就不会优化它。
以上来自于百度翻译 以下为原文 Start by getting rid of this. It is not legal to convert a pointer to a function to/from a pointer to void. Also make your counter in f1() volatile so the compiler doesn't optimize it away. |
|
|
|
我想我忘记了一些重要的事情:XC8V1.45,无论参数类型是什么,如果我不使用函数,它不知怎么地被传递为NULL;我也尝试使用函数指针作为参数类型:,具有相同的结果。计数器也是易失性的,全局的,静态的和组合的。NS。计数器只是在那里看到函数的效果,如果有的话(最初它是一个NOP)。我只是在其他编译器VC,Keil(ARM)中尝试过相同的代码…没问题,即使不使用调用,函数指针也会正确地传递(当然编译器在参数转换中抱怨,但是它们不通过NULL)。这只是XC8,但我不知道为什么。顺便说一下,所有这些都是默认设置,因为我只测试编译器如何用这些与硬件无关的C语句来操作。
以上来自于百度翻译 以下为原文 I think I forgot something important to mention: XC8 v1.45 No matter what the parameter type is, if I don't use the function somehow it's passed as NULL; I also tried using the function pointer as argument type: , with identical results. As well, the counter was volatile, global, static and combinations. The counter is just there to see the effect of the function, if any (initially it was instead a NOP). I just tried same code in other compilers VC, Keil (ARM)... no problem, the function pointer is passed correctly even without using the call (of course compilers complain in the parameter conversion, but they don't pass NULL). It's just XC8, but I don't why. Btw, all of them with default settings for all since I'm only testing how the compiler behaves with these C sentences not related to hardware at all. |
|
|
|
你所展示的代码没有任何副作用,所以你不能对它所做的有任何期望。事实上,它正确地做了什么,而不是按照你所期望的方式,这并不意味着编译器出现问题,它也不象另一个编译器。如果你纠正函数指针,使计数器易失,并调用函数,计数器增加吗?
以上来自于百度翻译 以下为原文 The code you've shown has no side effects, so you can't have any expectations about what it does. The fact that it correctly does nothing but not in the way you expect doesn't indicate a problem with the compiler, nor does it not behaving like another compiler. If you correct the function pointer, make the counter volatile, and call the function, does the counter increment? |
|
|
|
如果函数执行,计数器将递增,但执行它必须不是空的。只有在执行前执行函数时才会发生。使我困惑的是什么。Ie:如果你已经定义了函数-AdDR,那么当调用主α1时,如果添加了一个间接函数调用,当调用时,第3个问题是第1个问题。它总是接收0x000,除非你提出一个调用先前函数(α2)或间接(α3)的句子。如果我定义了一个函数,并把它传递给一个函数,我希望它有地址,而不是0x000。看起来编译器正在优化它(如果我不记得其他线程坏了),并且因为函数不直接使用,并且没有直接分配给函数指针,所以它不被使用。所以…远离的。但我不确定是不是这样,或者是另一回事。因为禁用优化不会改变任何东西。PS:我讨厌脚本服务器…必须编辑5次才能“正确”。
以上来自于百度翻译 以下为原文 The counter increments if the function executes, but to execute it must be not NULL.. and it only happens if the function is executed before asigning... what puzzles me. Ie: If you have defined function_addr as follow, void function_addr (const void * data) { ufun.addr = data; } When calling in main #1 main() { function_addr(f1) -> it receives NULL } #2 main { f1() function_addr(f1) -> it receives the correct address } Now, if an indirect function call is added as, void function_addr (const void * data) { ufun.addr = data; ufun.function(); <---- } When calling, #3 main() { function_addr(f1) -> Receives correct address. } The problem is #1. It always receives 0x0000 unless you place a sentence calling the function previously (#2) or indirectly (#3). If I have a function defined and I pass it to a function I expect having the address, not 0x0000. Looks the compiler is optimizing it (if I dont remember bad from other threads), and since the function is not used directly and not assigned to a function pointer directly, it's "not" used.. so... removed. But I'm not sure if it is the case or is a different thing., since disabling optimizations does not change anything. PS: I hate the script server.... had to edit 5 times to be "correct". |
|
|
|
那个代码仍然错误地使用空洞,而且我看不到任何波动。把一个完整的例子,有副作用,让其他人可以试试。
以上来自于百度翻译 以下为原文 That code still uses void * incorrectly and I don't see anything volatile. Put together a complete example that has side effects so others can try it. |
|
|
|
我怀疑OP不理解“副作用”意味着什么,或者优化编译器可以自由丢弃没有任何副作用的代码。
以上来自于百度翻译 以下为原文 I suspect the OP does not understand what "side effects" means, or that an optimising compiler is free to discard code which does not have any side effects. |
|
|
|
在我看来,如果检测到函数指针,这个“优化”应该立即被编译器禁用。当然,我们离Skynet很远(不幸的是……)
以上来自于百度翻译 以下为原文 In my opinion, if function pointers are detected, this "optimization" should be disabled immediately by the compiler. But of course we're far from Skynet (unfortunately...) |
|
|
|
对我来说,使用函数的指针意味着使用函数。显然,XC8的处理方式不同。它相信,函数只有在程序中的某个地方调用时才使用。因此,使用未使用函数的指针产生零。我相信这是违反标准的,它指出,任何指向“真实”的指针都与NULL不同。因此,即使一个函数被优化了,你仍然应该能够分辨NULL和函数的指针。我不明白为什么这是个问题。一般来说,你不需要任何地方不使用的函数,而在实际程序中会有NoUCH函数。
以上来自于百度翻译 以下为原文 To me, the fact that you take a pointer of the function means the function is used. Apparently, XC8 handles this differently. It believes, the function is used only when it's called somewhere in the program. Thus taking the pointer of an unused function yields zero. I believe this is a violation of the standard which says that pointers to anything "real" is different from NULL. Thus, even a function is optimized away, you still should be able to tell apart NULL and the pointer to the function. I don't see why this is a problem. Generally, you don't need a function which is not used anywhere, and in real program there will be no such functions. |
|
|
|
在应用“IF”规则之后,在该代码中没有指针或函数。源代码没有副作用。只要编译器生成的目标代码也没有副作用,它是正确的。编译器什么也不做并不重要。它可以恰好没有产生任何输出(我很惊讶它没有这样做)。
以上来自于百度翻译 以下为原文 There are no pointers or functions in this code after the "as-if" rule is applied. The source code has no side effects. As long as the object code generated by the compiler also has no side effects, it is correct. It doesn't matter what path the compiler takes in doing nothing. It could just as correctly generate no output at all (and I'm surprised it didn't do this). |
|
|
|
我同意。这在这个简单的例子中不是问题,但是这个例子是一个更大的软件的简化(我必须减少它来发现问题,因为一些测试函数调用了隐藏问题的地方)。代码A将函数暴露于其他不相关的代码B。(a)必须对在运行时可能发生突变的函数进行编程,而不是由A使用,但对于B,它们必须始终存在。由于提供函数给B的Is,想象潜在的错误:一个F1和F2,F2由A而不是F1使用,所以编译器将生成F1的空引用,并将其存储为NULL;B将找到空函数引用。坏的。即使在B中添加空校验作为良好的实践,也很难检测出问题的本质,因为NULL不是逻辑问题或开发者错误,而只是编译器。XC8的一些经验(它是一个很好的同步错误列表,它被认为是有效的,但它们不在C90/99中),在转移到链中的下一个链接之前,我做了一些简单的测试。我认为这个案例将是一个很好的候选者,它是一个警告类型的“引用函数但未被使用”,而不是S。通常丢弃它。限定符、范围等。注意它使用全局变量,它可以间接地使用在代码的另一个地方(实际上我做了,与我没有调用函数的结果一样)。至少如果它不生成代码,我希望有一个警告。现在我尝试了4个编译器,XC8是唯一一个使地址无效的方法,它们都发出了关于“空隙*”和铸件的正确警告,但是XC8将地址无效。即使使用“函数指针类型”作为参数,而不是“空洞*”-按下警告-它不会改变结果。恢复:-看起来XC8丢弃函数,如果它认为它们不被使用。引用它们是不够的。-禁用优化不会改变任何东西(行为是否在编译器引擎中嵌入?)-微芯片开发人员给出了一个解决办法。谢谢大家的时间。
以上来自于百度翻译 以下为原文 I agreed. This is not a problem in this simple example, but the example is a simplification of a bigger piece of software (I had to reduce it to find the problem since some test function calls where hidding the problem). That code A is exposing functions to other un-related code B. Someone (A) has to program the functions that can mutate in run-time and not neccesarily used by A but for B they must exist always. Since A is which supplies the functions to B, imagine the potential bug: A supplies f1 and f2, f2 is used by A but not f1, so the compiler would generate a NULL reference for f1 and it would be stored as NULL; B would find a NULL function reference. Bad. Even adding NULL checks in B as good practice, it would be hard to detect the nature of the problem since the NULL is not a logic problem or developer bug, just the compiler. Some experience with XC8 (and a nice list of syntatic errors it accepts as valid but they aren't in C90/99), led me to make some simple tests before moving to the next link in the chain. I think this case would be a perfect candidate for a warning sort of "function referenced but not used" instead silently discarding it. Qualifiers, scope, etc. Notice it uses a global variable and it could be used indirectly in another place of the code (in fact I did, with same results as far as I didn't call the function). At least if it was going to not generate code I'd expect a warning. I tried now with 4 compilers and XC8 is the only one making the address NULL; all of them issue the proper warnings about the "void *" and castings, but XC8 is NULLing the address. Even using a "function pointer type" as parameter instead the "void *" -supressing the warnings-, it does not change the result. Resume: -It looks XC8 discards functions if it thinks they are not used. Referencing them is not enough. -Disabling optimizations does not change anything (behavior deelply embedded in the compiler engine?). -Microchip developers tip above gives a workaround. Thanks for your time guys. |
|
|
|
XC8不像其他编译器。XC8实际上读取您的代码来处理您选择了一个几乎不能处理C代码的LAME CPU的事实。它的间接指令有限,无法处理正确的堆栈。编译器列出了它的局限性。你也可以阅读有关OCG的文章。编译后的堆栈是什么。其他编译器接受我的技巧,并不意味着你的代码是符合标准的。或者您没有使用非标准编译器扩展。有一个关键字来保存函数(我不记得它),但是要知道,如果编译器不能确定调用堆栈,它会做一些低效的事情来让代码工作。它可能比较慢,或者使用附加RAM。
以上来自于百度翻译 以下为原文 XC8 is not like other compilers. XC8 actually reads your code to deal with the fact you have chosen a lame CPU that can barely handle C code. It has limited instructions for indirection, and can not handle a proper stack. The compiler lists it limitations. You can also read about OCG. And what a compiled stack is. The other compilers accept my tricks, does not mean your code is standards compliant. Or that you are not using non standard compiler extensions. There is a key word to keep functions (I do not recall it) but know that if the compiler can not determine the call stack it will do some inefficient things to make you code work. It may be slower, or use addional ram. |
|
|
|
这些是我在编译你的代码时发出的警告——警告=- 9:
以上来自于百度翻译 以下为原文 These are the warnings I get compiling your code at --warn=-9: |
|
|
|
编译器可以做任何它想要的,但是效果必须是相同的。显然,如果你把函数的地址分配给一个变量,那么你就把地址与null进行比较,比较必须产生错误。@ OP:XC8用指针做了很大的优化。当你把所有东西编译在一起时,指针的大小可能会改变,所以你甚至不能依赖于从编译到编译的大小相同的指针,或者所有指针都是相同大小的。
以上来自于百度翻译 以下为原文 The compiler can do anything it wants, but the effect must be the same. Clearly, if you get the address of a function and assign it to a variable, then you compare the address to NULL, the comparison must yield false. @OP: XC8 does heavy optimizations with pointers. It all works when you compile everything together, however the pointer size may change, so you cannot even rely on pointers being the same size from compilation to compilation, or that all pointers are of the same size. |
|
|
|
外部效应必须相同。C没有检查运行程序的内部状态(即,调试)的概念。如果OP要添加指针值的PROTF并将其发送到UART,那么程序必须有不同的行为。
以上来自于百度翻译 以下为原文 The external effect must be the same. C has no concept of inspecting the internal state of a running program (i.e., debugging). If the OP were to add printf of the pointer value and sent it to the UART, then the program would have to behave differently. |
|
|
|
……但是如果你只处理这个地址,编译器仍然可以对错误结果进行硬编码。
以上来自于百度翻译 以下为原文 ...but if that's all you do with the address, the compiler could still hard-code the false result. |
|
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
5132 浏览 9 评论
1985 浏览 8 评论
1914 浏览 10 评论
请问是否能把一个ADC值转换成两个字节用来设置PWM占空比?
3153 浏览 3 评论
请问电源和晶体值之间有什么关系吗?PIC在正常条件下运行4MHz需要多少电压?
2213 浏览 5 评论
702浏览 1评论
593浏览 1评论
有偿咨询,关于MPLAB X IPE烧录PIC32MX所遇到的问题
476浏览 1评论
PIC Kit3出现目标设备ID(00000000)与预期的设备ID(02c20000)不匹配。是什么原因
608浏览 0评论
499浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-5 09:45 , Processed in 1.973412 second(s), Total 108, Slave 92 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号