"The input/output library <stdio.h> shall not be used."
"The input/output library <stdio.h> shall not be used."
我正在阅读 JSF AV C++ Coding Standards 规则 22 说:
AV Rule 22 (MISRA Rule 124, Revised)
The input/output library <stdio.h>
shall not be used.
有什么理由不使用<stdio.h>
?
我知道这些规则适用于 C++,我们可以使用 <iostream>
...但是 <stdio.h>
有什么问题?
最明显的问题是 printf
、scanf
及其各种同类(例如 sprintf
)缺乏类型安全。
除了类型安全问题外,scanf
和 sprintf
系列还很难确保不会出现缓冲区溢出。可以做到,但并非微不足道,而且似乎只有极少数 C 程序员完全知道如何处理此类任务。
时不时会有这样的问题,关于为什么某些编码标准要求这样或那样。
正确答案应该始终是:无论该编码标准的作者意图如何。有时,编码标准会给出其规则的原因;这个显然没有。因此,我们只能猜测您问题的答案可能是什么。
因此我将添加我自己的猜测:
飞行器听起来真的很严肃,对正确性和稳健性要求极高。 printf
、scanf
等使编写代码变得容易,这些代码可以愉快地通过编译器但在 运行 时间创建未定义的行为。
那些 C 函数确实比普通的 C++ 流有一个优势:格式字符串使编写国际化代码变得更容易。考虑这个使用 std::ostream
快速制作的示例,用于某些 UI 组件,例如客户管理应用程序中的按钮标签:
os << "Update customer\n";
您可能想要动态添加客户的姓名:
os << "Update " << customer_name << "\n";
并且您可能想要动态插入 "Update" 的外语单词:
os << InternationalString(id_update) << " " << customer_name << "\n";
然而,这本质上是以英语为中心的。它将生成正确的英文字符串,如 "Update John" 或 "Update Joe",但例如德语失败,它有 不同的语法 并且需要像 "John aktualisieren" 或 "Joe aktualisieren" 这样的字符串,在这种情况下名称在动词前面。
这是格式字符串的亮点:
sprintf(s, FormatString(id_update_customer), customer_name);
根据应用程序的语言设置,这样的 FormatString
函数可能 return "Update %s"
或 "%s aktualisieren"
.
不过,这还是很危险的。事实上,如果我上面的示例中的 customer_name
是 std::string
,那么您已经有未定义的行为了。
像 Boost.Format 这样的库试图将格式字符串的灵活性与流的类型安全性结合起来。
回到您的实际问题,我的猜测是国际字符串的灵活性在飞行器业务中并不是一个大问题。
如您所见,编码标准的各个方面都可以进行详尽的讨论。个别规则的原因可能并不总是那么明显,它们通常与编写标准的应用领域有关。
如果你不能问编码标准的作者,那么你的问题就真的没有答案。
此 JSF C++ 标准引用了 MISRA-C:1998,两者都与安全关键系统中 C 语言的使用有关。最新标准 MISRA-C:2012 已更新(提供更多原理和更好的示例),MISRA Rule 124 现在是 Rule 21.6 "The Standard Library input/output functions shall not be used"。
基本原理非常简单:流和文件 I/O 具有未指定、未定义和实现定义的相关行为。指南中还包括对描述这些不可预测行为的 C 标准(C90 和 C99)部分的引用。
如果实际实施定义明确或代码显示不重要,则可以(通过偏差过程)打破规则。
我正在阅读 JSF AV C++ Coding Standards 规则 22 说:
AV Rule 22 (MISRA Rule 124, Revised)
The input/output library
<stdio.h>
shall not be used.
有什么理由不使用<stdio.h>
?
我知道这些规则适用于 C++,我们可以使用 <iostream>
...但是 <stdio.h>
有什么问题?
最明显的问题是 printf
、scanf
及其各种同类(例如 sprintf
)缺乏类型安全。
除了类型安全问题外,scanf
和 sprintf
系列还很难确保不会出现缓冲区溢出。可以做到,但并非微不足道,而且似乎只有极少数 C 程序员完全知道如何处理此类任务。
时不时会有这样的问题,关于为什么某些编码标准要求这样或那样。
正确答案应该始终是:无论该编码标准的作者意图如何。有时,编码标准会给出其规则的原因;这个显然没有。因此,我们只能猜测您问题的答案可能是什么。
因此我将添加我自己的猜测:
飞行器听起来真的很严肃,对正确性和稳健性要求极高。 printf
、scanf
等使编写代码变得容易,这些代码可以愉快地通过编译器但在 运行 时间创建未定义的行为。
那些 C 函数确实比普通的 C++ 流有一个优势:格式字符串使编写国际化代码变得更容易。考虑这个使用 std::ostream
快速制作的示例,用于某些 UI 组件,例如客户管理应用程序中的按钮标签:
os << "Update customer\n";
您可能想要动态添加客户的姓名:
os << "Update " << customer_name << "\n";
并且您可能想要动态插入 "Update" 的外语单词:
os << InternationalString(id_update) << " " << customer_name << "\n";
然而,这本质上是以英语为中心的。它将生成正确的英文字符串,如 "Update John" 或 "Update Joe",但例如德语失败,它有 不同的语法 并且需要像 "John aktualisieren" 或 "Joe aktualisieren" 这样的字符串,在这种情况下名称在动词前面。
这是格式字符串的亮点:
sprintf(s, FormatString(id_update_customer), customer_name);
根据应用程序的语言设置,这样的 FormatString
函数可能 return "Update %s"
或 "%s aktualisieren"
.
不过,这还是很危险的。事实上,如果我上面的示例中的 customer_name
是 std::string
,那么您已经有未定义的行为了。
像 Boost.Format 这样的库试图将格式字符串的灵活性与流的类型安全性结合起来。
回到您的实际问题,我的猜测是国际字符串的灵活性在飞行器业务中并不是一个大问题。
如您所见,编码标准的各个方面都可以进行详尽的讨论。个别规则的原因可能并不总是那么明显,它们通常与编写标准的应用领域有关。
如果你不能问编码标准的作者,那么你的问题就真的没有答案。
此 JSF C++ 标准引用了 MISRA-C:1998,两者都与安全关键系统中 C 语言的使用有关。最新标准 MISRA-C:2012 已更新(提供更多原理和更好的示例),MISRA Rule 124 现在是 Rule 21.6 "The Standard Library input/output functions shall not be used"。
基本原理非常简单:流和文件 I/O 具有未指定、未定义和实现定义的相关行为。指南中还包括对描述这些不可预测行为的 C 标准(C90 和 C99)部分的引用。
如果实际实施定义明确或代码显示不重要,则可以(通过偏差过程)打破规则。