2012-03-08 46 views
7

我对以下问题感到困惑:如何保持“静态”标签的优势,但仍然能够在现场调试生产代码?静态与非静态函数 - 调试嵌入式系统上下文

在客户现场并没有发生意外的行为,只有在那里。在许多情况下,选择执行调试可以节省很多工作量并提供非常快速的响应。这样的调试通常涉及检查函数行为,这将我们带入“静态”定义。

静态函数无法从调试shell进行调试,如放置断点或执行它。另一方面,将所有函数定义为公共导致代码结构和优化悲伤。

我知道像编译至少两个不同的构建,一个与静态和一个没有,但这很适合自动化测试,而不是最终生产构建,最终熄灭。

会从你身边感谢你的一些见解,主要是你如何解决(如果有的话)这个困境。或者将问题改写为:“什么更重要?

关于“静态”的一个很好的讨论C here

+1

你的意思是你不能在声明为'static'的函数中设置断点?在C中,“静态”函数只是普通函数,但不能从其他“翻译单元”调用。除非它们已经被优化掉,否则任何东西都不应该阻止它们的调试,远程或本地调试。 – 2012-03-08 09:27:22

+1

您可以定义一个指向您的静态函数的全局指针,并使用它的值来设置静态函数的断点。你甚至可以把这个指针设置为volatile,以防止编译器将其作为未使用的消除。 – 2012-03-08 10:05:56

+0

@JoachimPileborg据我所知,静态函数不会进入符号表(即使使用编译器标记),因此,调试是不可能的(如断点)。 – EdwardH 2012-03-08 10:35:41

回答

1

一些调试器可以调试“静态”功能。有时静态函数会在调用站点上扩展,但这会使调试器的工作变得困难,有些调试器会放弃。 (调用网站的内联扩展实际上并不是特定于“静态”的属性,只是编译器更有可能这样做,因为他们“知道更多”关于该功能的信息 - 特别是,名称不可见当前转换单元之外,因此函数的代码可以完全省略如果所有呼叫都在行扩展)

它曾经是共同使用宏:

#ifndef STATIC 
# define STATIC static 
#endif 
... 
STATIC void somefunc() { ... } 

,然后打开宏进入调试版本的“无”。这很好,但是更好的是找到一个足够聪明的调试器来处理静态函数,即使它们是内联的扩展。

+0

宏解决了内部测试期间的问题,但是当问题出现在客户现场并且仅在那里时,宏并不适合。有时候,放一个调试版本可以消除这个问题。 – EdwardH 2012-03-08 10:48:59

1

你可以在调用静态函数的公共访问函数中放置一个断点吗?然后你可以至少检查进入的参数和返回值。如果问题仅出现在客户现场,并且您的单元测试/集成测试没有显示您希望这些功能接收到的输入问题,则问题可能是这些功能正在获取输入(或输入序列,如果函数有状态)你没有预料到,这意味着实际的问题可能超出了你所看到的静态函数。

如果您已经怀疑您知道哪个静态函数包含此问题,并且您知道您怀疑会导致问题的输入类型,那么您可以在发布版本中添加一个简单的单元测试函数,以检查您的错误疑似。当然,如果这个功能直接控制,这会变得很复杂,例如一台6吨的起重机,在这种情况下,您可能需要编写两个版本的功能,一个带有控制起重机的模型,然后运行测试。

尽可能少但并非不可能,从不排除发行版和调试版本之间的编译器不一致问题。我们都喜欢认为编译器是可靠的,包括我在内,但是有些事情发生。我看到在你的回应torek,给客户一个调试版本有时修复了问题...

+0

调试模块的API并不总是足够的,尤其是当您已经怀疑私有函数存在问题时。我完全同意你行使所需测试的观点,但是,这并不总是适用于嵌入式环境。很多时候我们都在讨论单元测试可能无法涵盖的事件的排序和异步处理。 – EdwardH 2012-03-09 09:40:26

3

我认为根本问题不是“你是否与'静态'?”,它是“你准确测试你发货了吗?”?“对于嵌入式代码,如果您在Debug版本上进行了大部分测试,然后发布使用不同选项编译的Release版本,那么您实际上将未经测试的代码发送给您的客户。当您在硬件附近运行时,时序或内存访问模式(优化器可以轻松引入)的微小变化可能会导致系统行为发生重大变化。

我目前的策略是发布调试版本,配置为尽可能多的优化,因为我可以在调试时站起来。没有静态函数,尽可能多地向调试器显示状态。

是的,我放弃了一些可能的编译器生成的效率,但只要我确保Debug版本足够快以满足其要求,那就不是问题。最终的结果是,我发布的代码与我在整个发布周期中测试的代码完全相同 - 没有优化器产生的惊喜。

+0

值得一提的是,“静态”用法不仅与效率有关,而且在很多方面都是面向对象的概念(如声明和实现适当的分离,所以其他编码器不会绕过定义的API/s)。你提出的新问题在这里值得一个单独的话题,有几个优点和缺点需要考虑。 – EdwardH 2012-03-09 09:34:15

+0

在封装和可视性方面,将函数从相应的头文件中取出几乎和静态声明一样好。命名也可以提供帮助。“你为什么从Module2.c调用'module1DoSomething_private()'?”是一个很好的问题在审查中要求... – AShelly 2012-03-09 18:24:25

+1

另请参阅http://stackoverflow.com/q/420343/10396 – AShelly 2012-03-09 18:45:58