检查 nullptr 100% 是否可以防止有关内存布局的段错误?
does checking for nullptr 100% protect from segfault regarding memory layout?
假设我正在迭代一个数组,但超出了这个数组,因为我的循环很愚蠢。
如果内存中的某个对象直接位于与此数组相同类型的此数组之后,则可以
检查 array[invalid_index] == nullptr
保护我?
检查索引(大小未知)是否对 C 数组有效的正确方法是什么?
不,检查 nullptr
并不能保护您。完全没有。 0%.
问题数组是您创建的。检查索引是否有效的正确方法是了解您创建的数组的大小(您所做的;记住:创建该数组的是您),然后检查指标在范围内。更好的是,编写代码时索引首先不会超出范围,因此不需要检查开始于...
除了数组最后一个元素之后的假设元素外,尝试单独 计算(甚至不访问,只计算)一个元素的地址不是数组的一部分会立即调用未定义的行为 [expr.add]/4. And, without exception, attempting to access an element that is not actually an element of an array always invokes undefined behavior no matter what. 100%. The built-in subscript operator is just shorthand for computing the address of the given element and accessing the object at that address [expr.sub]/1。因此,在进入未定义行为领域之前,您实际上甚至没有达到 可以 将您读取的值与 nullptr
进行比较的程度……
无法通过指向数组第一个元素的指针来确定数组的大小。您需要以某种方式传达尺寸。
常见的策略是将数组保持为数组并通过类型系统传达大小,将大小作为单独的值提供或使用标记值(如 c 字符串中的空字符)。在 C++ 中,建议使用 std::vector
或 std::array
,它们始终知道自己的大小。
尝试取消引用超出该数组边界的数组元素是未定义的行为。一旦您尝试阅读 array[invalid_index]
,您就会遇到未定义的行为。所以不可能将 array[invalid_index]
用于任何有用的目的,包括边界检查。 nullptr
在这里完全没有作用。
这种支票不会保护你。
许多 C API 与使用它的程序员签订了某种合同,他们将遵守 API 指定的约定,而无需对该合同进行任何严格的机械执行。例如,基于 C 的字符串 API 主要断言字符串始终以空值终止,并且任何基于 C 的字符串 API 的正确使用将假定并依赖于以空值终止的字符串。
当这个合同就位时,通常认为执行这些类型的检查是安全的,因为传递给你字符串的人应该保证这个合同,通常通过使用额外的 null 值填充字符串或数据结构来专门明确地履行此合同,如下所示:
char string[13] = "Hello World!"; //string[12] contains the value 0
/*...*/
char const* str = string;
do {
char curr = *str++;
if(curr == 0)
break;
/*...*/
} while(true);
在大多数基于 C 的字符串 API 中,该代码被认为是 "safe" 在保证合同的特定上下文中。
但这取决于程序员自己的表现,并且无法保证。程序员用他们的代码和类似这样的行为不当并不需要太多:
char string[12] = "Hello World";
string[11] = '!';
会立即破坏我刚才显示的字符串循环。这就是为什么 C++ 程序员觉得(在我看来是正确的)这些类型的检查是不安全的:除非您相信您的用户(程序员)遵守您的规则,否则无法保证它们是正确的。
这就是为什么我们更喜欢 API 不会像这样意外损坏的原因。
std::string string = "Hello World!";
for(char curr : string) { //for-each loop, intrinsically safe unless the iterators are improperly implemented
/*Do whatever with curr*/
}
所以回到你原来的问题:处理这个问题的安全方法是使用专门设计来保护我们安全的物品。使用 std::array<T, N>
而不是 T arr[N]
,这将允许使用 for-each 循环。如果您需要使用基于索引的迭代,在性能不是很重要的任何情况下,首选 at(index)
而不是 [index]
。这些做法将使您的代码安全,而不仅仅是相信您的数据配置正确。
does checking for nullptr 100% protect from segfault
没有。访问无效内存的方式有很多种,空指针只是其中一种。
你必须做的是避免所有未定义的行为。
What is the correct way to check whether an index (size is not known) is valid for a C array?
检查方法是与数组的大小进行比较:
if (index < size)
// valid
如果您不知道数组的大小,则无法检查有效性。错误的其他典型来源是错误地假设数组的大小或生命周期。
假设我正在迭代一个数组,但超出了这个数组,因为我的循环很愚蠢。
如果内存中的某个对象直接位于与此数组相同类型的此数组之后,则可以
检查 array[invalid_index] == nullptr
保护我?
检查索引(大小未知)是否对 C 数组有效的正确方法是什么?
不,检查 nullptr
并不能保护您。完全没有。 0%.
问题数组是您创建的。检查索引是否有效的正确方法是了解您创建的数组的大小(您所做的;记住:创建该数组的是您),然后检查指标在范围内。更好的是,编写代码时索引首先不会超出范围,因此不需要检查开始于...
除了数组最后一个元素之后的假设元素外,尝试单独 计算(甚至不访问,只计算)一个元素的地址不是数组的一部分会立即调用未定义的行为 [expr.add]/4. And, without exception, attempting to access an element that is not actually an element of an array always invokes undefined behavior no matter what. 100%. The built-in subscript operator is just shorthand for computing the address of the given element and accessing the object at that address [expr.sub]/1。因此,在进入未定义行为领域之前,您实际上甚至没有达到 可以 将您读取的值与 nullptr
进行比较的程度……
无法通过指向数组第一个元素的指针来确定数组的大小。您需要以某种方式传达尺寸。
常见的策略是将数组保持为数组并通过类型系统传达大小,将大小作为单独的值提供或使用标记值(如 c 字符串中的空字符)。在 C++ 中,建议使用 std::vector
或 std::array
,它们始终知道自己的大小。
尝试取消引用超出该数组边界的数组元素是未定义的行为。一旦您尝试阅读 array[invalid_index]
,您就会遇到未定义的行为。所以不可能将 array[invalid_index]
用于任何有用的目的,包括边界检查。 nullptr
在这里完全没有作用。
这种支票不会保护你。
许多 C API 与使用它的程序员签订了某种合同,他们将遵守 API 指定的约定,而无需对该合同进行任何严格的机械执行。例如,基于 C 的字符串 API 主要断言字符串始终以空值终止,并且任何基于 C 的字符串 API 的正确使用将假定并依赖于以空值终止的字符串。
当这个合同就位时,通常认为执行这些类型的检查是安全的,因为传递给你字符串的人应该保证这个合同,通常通过使用额外的 null 值填充字符串或数据结构来专门明确地履行此合同,如下所示:
char string[13] = "Hello World!"; //string[12] contains the value 0
/*...*/
char const* str = string;
do {
char curr = *str++;
if(curr == 0)
break;
/*...*/
} while(true);
在大多数基于 C 的字符串 API 中,该代码被认为是 "safe" 在保证合同的特定上下文中。
但这取决于程序员自己的表现,并且无法保证。程序员用他们的代码和类似这样的行为不当并不需要太多:
char string[12] = "Hello World";
string[11] = '!';
会立即破坏我刚才显示的字符串循环。这就是为什么 C++ 程序员觉得(在我看来是正确的)这些类型的检查是不安全的:除非您相信您的用户(程序员)遵守您的规则,否则无法保证它们是正确的。
这就是为什么我们更喜欢 API 不会像这样意外损坏的原因。
std::string string = "Hello World!";
for(char curr : string) { //for-each loop, intrinsically safe unless the iterators are improperly implemented
/*Do whatever with curr*/
}
所以回到你原来的问题:处理这个问题的安全方法是使用专门设计来保护我们安全的物品。使用 std::array<T, N>
而不是 T arr[N]
,这将允许使用 for-each 循环。如果您需要使用基于索引的迭代,在性能不是很重要的任何情况下,首选 at(index)
而不是 [index]
。这些做法将使您的代码安全,而不仅仅是相信您的数据配置正确。
does checking for nullptr 100% protect from segfault
没有。访问无效内存的方式有很多种,空指针只是其中一种。
你必须做的是避免所有未定义的行为。
What is the correct way to check whether an index (size is not known) is valid for a C array?
检查方法是与数组的大小进行比较:
if (index < size)
// valid
如果您不知道数组的大小,则无法检查有效性。错误的其他典型来源是错误地假设数组的大小或生命周期。