C 使tolower为静态

C 使tolower为静态,c,static,inline,misra,tolower,C,Static,Inline,Misra,Tolower,我需要使标准库函数降低静态范围,而不是公共范围 我使用的是MISRA C:2004,使用的是IAR嵌入式工作台编译器。编译器正在将tolower声明为内联: inline int tolower(int _C) { return isupper(_C) ? (_C + ('A' - 'a')) : _C; } 我从编译器中得到以下错误: Error[Li013]: the symbol "tolower" in RS232_Server.o is public but

我需要使标准库函数降低静态范围,而不是公共范围

我使用的是MISRA C:2004,使用的是IAR嵌入式工作台编译器。编译器正在将tolower声明为内联:

  inline
  int tolower(int _C)
  {
    return isupper(_C) ? (_C + ('A' - 'a')) : _C;
  }
我从编译器中得到以下错误:

Error[Li013]: the symbol "tolower" in RS232_Server.o is public but
is only needed by code in the same module - all declarations at
file scope should be static where possible (MISRA C 2004 Rule 8.10)  
以下是我建议的解决方案:

在虚拟环境中,在另一个模块中使用tolower,以便 由多个模块需要。 在不使用tolower的情况下实现功能。这是一个嵌入式系统。 添加静态宏,默认情况下定义为空,但可以 在包含ctype.h头文件之前定义为static。 我正在寻找解决MISRA链接器错误的方法。我更愿意只为RS232_服务器翻译单元使tolower函数为静态。如果我在标准头文件中使tolower函数为静态,它可能会影响其他未来的项目

编辑1: 编译器是针对ARM处理器的IAR Embedded Workbench 6.30。 我在32位模式下使用的是ARM7TDMI处理器,而不是Thumb模式。 tolower函数与调试端口一起使用

编辑2: 我还得到了_LocaleC_isupper和_LocaleC_tolower的错误

解决方案: 根据Michael Burr的建议,我将问题通知了供应商。 由于本地化的原因,我决定不重写库例程 问题。 我在main.c文件中实现了一个函数指针,正如 gbulmer;然而,这将是令人难以置信的评论,因为它应该 在IAR解决其问题后被移除。
谁卖MISRA链接器?它似乎有一个疯狂的错误

你能用地址int*fooint=tolower来解决这个问题吗;在文件范围内

编辑:我的理由是: A.这是这十年来我见过的最愚蠢的事情,所以它可能是一个bug,但是 B将其推向一个边缘箱,一个通过全局文件导出其名称的符号可能会使其关闭

要使其成为正确的行为,即不是一个bug,必须是一个MISRA错误,包括任何库函数一次,如初始化系统计时器、初始化看门狗计时器等,这伤了我的头

编辑:另一个想法。再次基于这是一个边缘案例错误的假设

理论:也许编译器正在内联和生成函数的实现。那么这个函数当然不会被调用。所以链接器规则看到了未调用的函数

GNU提供了防止内衬的选项。 你能用tolower做同样的事吗?这会改变错误吗?你可以做一个测试

#define inline /* nothing */
在包含ctype.h之前,请先取消定义宏

另一个测试是定义:

#define inline static inline
在包含ctype.h之前,这是我期望的内联版本

编辑2: 我认为有一个错误应该报告。我想我会有一个变通办法。我会接受他们的建议

晚上睡觉后,我强烈怀疑问题是内联int-tolower,而不是静态内联int-tolower或int-tolower,因为这是最有意义的。拥有一个未被调用的公共函数似乎是程序中bug的症状

即使有文档,所有的编码方法都有缺点

我强烈支持OP,我不会更改标准头文件。我认为有几个原因。例如,工具链的未来升级会附带一组新的标题,如果旧应用程序得到维护,它将被破坏。或者简单地在不同的机器上构建应用程序会产生错误,合并两个显然正确的应用程序可能会产生错误。这不可能带来什么好结果-一百

使用定义。。。使错误消失。我不喜欢使用宏来更改标准库。这似乎是一个长期坏主意的种子。如果将来程序的另一部分使用具有类似问题的另一个函数,“修复”的应用会变得更糟。一些没有经验的开发人员可能会得到维护代码的工作,并且“学会”围绕include包装奇怪的define技巧是“正常”的做法。将include封装在奇怪的宏解决方案中成为公司的“惯例”,这一做法在修复多年后仍然存在-二十

使用命令行编译器选项关闭内联。如果这是可行的,并且语义是正确的,即在两个源文件中包含头并使用函数不会导致多定义函数,那么可以。我希望它会导致错误,但作为bug报告的一部分,它值得确认。它为将来出现的其他人设置了一个令人沮丧的陷阱。如果使用了不同的内联标准库函数,并且出于某种原因,用户必须查看生成的代码,则也不会包含该函数。他们可能会有点疯狂,想知道为什么内联不受尊重。我猜想他们之所以关注生成的代码,是因为性能至关重要。根据我的经验,人们会花很多时间看代码,在看构建脚本之前感到困惑 对于一个有效的程序。如果将抑制内联用作修复,我确实觉得在任何地方都这样做比在一个文件中这样做要好。至少语义是一致的,高层评论或文档可能会引起注意。任何使用构建脚本作为“快速检查”的人都会得到一致的行为,这可能会导致他们查看文档-1无任何内联-3无一个文件的内联

在第二个源文件中以虚假方式使用tolower。这样做的好处很小,构建系统不会被额外的编译器选项“感染”。此外,这是一个小文件,它将提供解释正在处理的错误的机会。我不太喜欢这个,但我更喜欢它,而不是摆弄标准标题。我现在担心的是它可能不起作用。它可能包含链接器无法解析的两个副本。我确实喜欢它比奇怪的“获取其地址并查看链接器是否关闭”要好,我认为这是一种测试边缘案例的有趣方式-二,

编写自己的tolower代码。我不了解应用程序的更广泛背景。我的反应不是用代码替换库函数,因为我关心的是引入更多代码和长期维护的测试和单元测试。我对字符I/O更为紧张,因为应用程序可能需要能够处理更广泛的字符集,例如UTF-8编码,而用户定义的tolower可能会失去同步。这听起来确实像是一个非常特殊的应用程序调试到一个端口,所以我可以应付。我不喜欢编写额外的代码来处理看起来像bug的东西,特别是如果它是商业软件的话-五,

您能否将错误转换为警告而不丢失所有其他检查?我仍然觉得这是工具链中的一个bug,所以我更希望它是一个警告,而不是沉默,这样就有了一个事件和一些文档的钩子,并且不太可能出现另一个错误。否则,请关闭错误+1警告0错误

关闭错误似乎会失去“公司意识”,即IMHO IAR应该向您提供解释和长期修复,但这似乎比搞乱构建系统、使用标准库向futz编写宏污点或编写自己的代码(这会增加成本)要好得多


可能只是我,但我不喜欢编写代码来解决商业产品中的缺陷。感觉这是供应商应该很高兴有机会证明其许可成本的地方。我记得微软就事件向我们收费,但如果问题被证明是他们的,那么事件和修复是免费的。正确的做法似乎是给他们一个赚钱的机会。产品会有bug,所以在没有机会修复的情况下默默地解决它似乎也没什么帮助

谁出售MISRA链接器?它似乎有一个疯狂的错误

你能用地址int*fooint=tolower来解决这个问题吗;在文件范围内

编辑:我的理由是: A.这是这十年来我见过的最愚蠢的事情,所以它可能是一个bug,但是 B将其推向一个边缘箱,一个通过全局文件导出其名称的符号可能会使其关闭

要使其成为正确的行为,即不是一个bug,必须是一个MISRA错误,包括任何库函数一次,如初始化系统计时器、初始化看门狗计时器等,这伤了我的头

编辑:另一个想法。再次基于这是一个边缘案例错误的假设

理论:也许编译器正在内联和生成函数的实现。那么这个函数当然不会被调用。所以链接器规则看到了未调用的函数

GNU提供了防止内衬的选项。 你能用tolower做同样的事吗?这会改变错误吗?你可以做一个测试

#define inline /* nothing */
在包含ctype.h之前,请先取消定义宏

另一个测试是定义:

#define inline static inline
在包含ctype.h之前,这是我期望的内联版本

编辑2: 我认为有一个错误应该报告。我想我会有一个变通办法。我会接受他们的建议

晚上睡觉后,我强烈怀疑问题是内联int-tolower,而不是静态内联int-tolower或int-tolower,因为这是最有意义的。拥有一个未被调用的公共函数似乎是程序中bug的症状

即使有文档,所有的编码方法都有缺点

我强烈支持OP,我不会更改标准头文件。我认为有几个原因。例如,工具链的未来升级会附带一组新的标题,如果旧应用程序得到维护,它将被破坏。或者简单地在不同的机器上构建应用程序会产生错误,合并两个显然正确的应用程序可能会产生错误。这不可能带来什么好结果-一百

美国 定义。。。使错误消失。我不喜欢使用宏来更改标准库。这似乎是一个长期坏主意的种子。如果将来程序的另一部分使用具有类似问题的另一个函数,“修复”的应用会变得更糟。一些没有经验的开发人员可能会得到维护代码的工作,并且“学会”围绕include包装奇怪的define技巧是“正常”的做法。将include封装在奇怪的宏解决方案中成为公司的“惯例”,这一做法在修复多年后仍然存在-二十

使用命令行编译器选项关闭内联。如果这是可行的,并且语义是正确的,即在两个源文件中包含头并使用函数不会导致多定义函数,那么可以。我希望它会导致错误,但作为bug报告的一部分,它值得确认。它为将来出现的其他人设置了一个令人沮丧的陷阱。如果使用了不同的内联标准库函数,并且出于某种原因,用户必须查看生成的代码,则也不会包含该函数。他们可能会有点疯狂,想知道为什么内联不受尊重。我猜想他们之所以关注生成的代码,是因为性能至关重要。根据我的经验,人们会花很多时间看代码,在看程序的构建脚本之前感到困惑。如果将抑制内联用作修复,我确实觉得在任何地方都这样做比在一个文件中这样做要好。至少语义是一致的,高层评论或文档可能会引起注意。任何使用构建脚本作为“快速检查”的人都会得到一致的行为,这可能会导致他们查看文档-1无任何内联-3无一个文件的内联

在第二个源文件中以虚假方式使用tolower。这样做的好处很小,构建系统不会被额外的编译器选项“感染”。此外,这是一个小文件,它将提供解释正在处理的错误的机会。我不太喜欢这个,但我更喜欢它,而不是摆弄标准标题。我现在担心的是它可能不起作用。它可能包含链接器无法解析的两个副本。我确实喜欢它比奇怪的“获取其地址并查看链接器是否关闭”要好,我认为这是一种测试边缘案例的有趣方式-二,

编写自己的tolower代码。我不了解应用程序的更广泛背景。我的反应不是用代码替换库函数,因为我关心的是引入更多代码和长期维护的测试和单元测试。我对字符I/O更为紧张,因为应用程序可能需要能够处理更广泛的字符集,例如UTF-8编码,而用户定义的tolower可能会失去同步。这听起来确实像是一个非常特殊的应用程序调试到一个端口,所以我可以应付。我不喜欢编写额外的代码来处理看起来像bug的东西,特别是如果它是商业软件的话-五,

您能否将错误转换为警告而不丢失所有其他检查?我仍然觉得这是工具链中的一个bug,所以我更希望它是一个警告,而不是沉默,这样就有了一个事件和一些文档的钩子,并且不太可能出现另一个错误。否则,请关闭错误+1警告0错误

关闭错误似乎会失去“公司意识”,即IMHO IAR应该向您提供解释和长期修复,但这似乎比搞乱构建系统、使用标准库向futz编写宏污点或编写自己的代码(这会增加成本)要好得多


可能只是我,但我不喜欢编写代码来解决商业产品中的缺陷。感觉这是供应商应该很高兴有机会证明其许可成本的地方。我记得微软就事件向我们收费,但如果问题被证明是他们的,那么事件和修复是免费的。正确的做法似乎是给他们一个赚钱的机会。产品会有bug,所以在没有机会修复的情况下默默地解决它似乎也没什么帮助

我建议您禁用此特定的MISRA检查,您应该能够仅为RS232_服务器翻译单元禁用此检查,而不是使用您建议的解决方法之一。在我看来,规则8.10的效用非常小,在建议的变通办法中跳过各种障碍似乎比仅仅禁用规则更可能带来更高的风险。请记住,MISRA的目的是降低C代码出现错误的可能性

请注意,MISRA认识到,在某些情况下,可能需要偏离规则,MISRA-C 2004中有记录在案的偏离程序第4.3.2节

如果出于任何原因您不想或不能禁用该规则,请在
我的意见是,您应该在自己的函数中重新实现tolower的功能,尤其是在不需要处理语言环境支持的情况下。与IAR一起发起支持事件也可能是值得的。您可以使用规则3.6来刺激它们,规则3.6规定,生产代码中使用的所有库都应按照[MISRA-C]编写。

我建议您禁用此特定的MISRA检查,您应该能够仅对RS232_服务器翻译单元执行此操作,而不是使用您建议的解决方法之一。在我看来,规则8.10的效用非常小,在建议的变通办法中跳过各种障碍似乎比仅仅禁用规则更可能带来更高的风险。请记住,MISRA的目的是降低C代码出现错误的可能性

请注意,MISRA认识到,在某些情况下,可能需要偏离规则,MISRA-C 2004中有记录在案的偏离程序第4.3.2节

如果出于任何原因您不想或不能禁用该规则,我认为您应该在自己的函数中重新实现tolower的功能,特别是如果您不需要处理语言环境支持的话。与IAR一起发起支持事件也可能是值得的。您可以使用规则3.6来刺激它们,规则3.6规定,生产代码中使用的所有库都应按照[MISRA-C]编写。

首先,MISRA-C:2004不允许内联或C99。即将到来的MISRA 2012将允许它。如果您试图通过MISRA-C:2004静态分析器运行C99或非标准代码,则所有赌注都将被取消。MISRA检查器应该为内联关键字提供一个错误

我相信符合MISRA-C标准的代码版本如下所示:

static uint8_t tolower(uint8_t ch)
{
  return (uint8_t)(isupper(ch) ? (uint8_t)((uint8_t)(ch + 'A') - 'a') : 
                                 ch);
}
对此有一些评论:MISRA鼓励字符文本使用char类型,但同时警告不要使用纯char类型,因为它具有实现定义的符号性。因此我改用uint8\u t。我认为假设存在具有负索引的ASCII表是愚蠢的

_C+'A'-'A'肯定不符合MISRA,因为MISRA认为它包含两个隐式类型提升。MISRA将字符文本视为char,而不是int,就像C标准一样

此外,必须在每个表达式之后将类型转换为基础类型。而且,由于?:运算符包含隐式类型提升,因此还必须将其结果类型转换为基础类型

由于这是一个相当不可读的烂摊子,最好的办法是完全忘记?:重写函数。同时,我们可以摆脱对有符号计算的不必要依赖

static uint8_t tolower (uint8_t ch)
{
  if(isupper(ch))
  {
    ch = (uint8_t)(ch - 'A');
    ch = (uint8_t)(ch + 'a');
  }
  return ch;
}
首先,MISRA-C:2004不允许内联或C99。即将到来的MISRA 2012将允许它。如果您试图通过MISRA-C:2004静态分析器运行C99或非标准代码,则所有赌注都将被取消。MISRA检查器应该为内联关键字提供一个错误

我相信符合MISRA-C标准的代码版本如下所示:

static uint8_t tolower(uint8_t ch)
{
  return (uint8_t)(isupper(ch) ? (uint8_t)((uint8_t)(ch + 'A') - 'a') : 
                                 ch);
}
对此有一些评论:MISRA鼓励字符文本使用char类型,但同时警告不要使用纯char类型,因为它具有实现定义的符号性。因此我改用uint8\u t。我认为假设存在具有负索引的ASCII表是愚蠢的

_C+'A'-'A'肯定不符合MISRA,因为MISRA认为它包含两个隐式类型提升。MISRA将字符文本视为char,而不是int,就像C标准一样

此外,必须在每个表达式之后将类型转换为基础类型。而且,由于?:运算符包含隐式类型提升,因此还必须将其结果类型转换为基础类型

由于这是一个相当不可读的烂摊子,最好的办法是完全忘记?:重写函数。同时,我们可以摆脱对有符号计算的不必要依赖

static uint8_t tolower (uint8_t ch)
{
  if(isupper(ch))
  {
    ch = (uint8_t)(ch - 'A');
    ch = (uint8_t)(ch + 'a');
  }
  return ch;
}

MISRA不是一个链接器,它是一套“安全”嵌入式代码的规则。IAR工具链可以配置为在您违反MISRA规则时让您知道。我理解MISRA是什么。但是链接器施加的配置/约束(抛出一个我可以处理的错误)似乎有一个严重的错误。我从未使用过IAR工具,但一些朋友说他们的工具笨重但坚固,所以我允许它可能不是IAR的链接器。但它可能是触发我认为是错误的其他原因。在RS232_服务器翻译单元中获取文件范围内的地址并不能解决错误。但是,我将其添加到main.c文件中,链接错误消失了:-@托马斯·马修斯——我假设这个效果类似于在一个伪函数中调用它,尽管可能稍微好一点,因为没有机器指令来调用它。有趣的你有能力向IAR提出事件吗?@gbulmer没有bug。MISRA-C:2004只允许C90,所以它不知道内联k

埃沃德。在这种情况下,内联很可能是一个编译器扩展。若编译器和静态分析器都是IAR,那个么它们的分析器很可能知道这个编译器扩展并忽略它。然后我们只剩下int-tolowerint了。MISRA不是一个链接器,它是一套“安全”嵌入式代码的规则。IAR工具链可以配置为在您违反MISRA规则时让您知道。我理解MISRA是什么。但是链接器施加的配置/约束(抛出一个我可以处理的错误)似乎有一个严重的错误。我从未使用过IAR工具,但一些朋友说他们的工具笨重但坚固,所以我允许它可能不是IAR的链接器。但它可能是触发我认为是错误的其他原因。在RS232_服务器翻译单元中获取文件范围内的地址并不能解决错误。但是,我将其添加到main.c文件中,链接错误消失了:-@托马斯·马修斯——我假设这个效果类似于在一个伪函数中调用它,尽管可能稍微好一点,因为没有机器指令来调用它。有趣的你有能力向IAR提出事件吗?@gbulmer没有bug。MISRA-C:2004只允许C90,所以它不知道内联关键字。在这种情况下,内联很可能是一个编译器扩展。若编译器和静态分析器都是IAR,那个么它们的分析器很可能知道这个编译器扩展并忽略它。然后我们剩下int-tolowerint\u C。我想我们同意这听起来像个bug。但是,可能还有其他东西触发了bug吗?你能写一个最小的程序,用tolower来看看它是否消失了吗?你能把ctype.h复制到一个本地目录,然后扔掉除了你需要的部分以外的所有东西吗?希望您能在该文件或更早的头文件中发现一些奇怪之处。我想我们同意这听起来像个bug。但是,可能还有其他东西触发了bug吗?你能写一个最小的程序,用tolower来看看它是否消失了吗?你能把ctype.h复制到一个本地目录,然后扔掉除了你需要的部分以外的所有东西吗?希望您能在该文件或更早的头文件中发现一些奇怪之处。+1 for“您可以使用规则3.6对其进行处理”,表示生产代码中使用的所有库都应按照[MISRA-C]进行编写。'Update:我删除了RS232_服务器翻译单元的规则8.10,但仍然得到链接错误。'-我肯定会引用规则3.6向IAR提交一个问题。谢谢你的建议。@Thomas:我的错误是只为一个编译单元禁用了该规则——因为该规则处理全局符号的行为,并且是由链接器实现的,所以我认为你必须在整个项目中禁用它。希望链接器会尊重这个设置。@Michael Burr:我认为改变整个项目的设置是件坏事。我希望为一个编译单元禁用它可以解决这个错误。这样可以将影响保持在最小的单位。但是,由于它不起作用,另一种选择是在整个项目中禁用它,这将使许多人无法获得质量目标。多数人的需求大于少数人的需求。“+1 for”你可以用规则3.6来刺激他们,它说生产代码中使用的所有库都应该按照[MISRA-C]来编写。更新:我删除了RS232_服务器翻译单元的规则8.10,但仍然得到了链接错误:-我肯定会引用规则3.6向IAR提交一个问题。谢谢你的建议。@Thomas:我的错误是只为一个编译单元禁用了该规则——因为该规则处理全局符号的行为,并且是由链接器实现的,所以我认为你必须在整个项目中禁用它。希望链接器会尊重这个设置。@Michael Burr:我认为改变整个项目的设置是件坏事。我希望为一个编译单元禁用它可以解决这个错误。这样可以将影响保持在最小的单位。但是,由于它不起作用,另一种选择是在整个项目中禁用它,这将使许多人无法获得质量目标。多数人的需求大于少数人的需求。“我认为您在确保编译器不处于C99模式并且配置为不允许扩展方面做得很好。然而,如果IAR想要公布一个符合MISRA的编译器,那么在ctype.h中应该有一个符合MISRA的tolower,编译器需要配置为使用MISRA兼容版本-该配置的要求应该由IAR在某处记录。我认为您在确保编译器不处于C99模式并且配置为不允许扩展方面做得很好。但是,如果IAR想要公布一个符合MISRA的编译器,那么ctype.h中应该有一个符合MISRA的tolower。如果允许,编译器需要配置为使用符合MISRA的版本-该配置的要求应由IAR somew记录 在这里