我最近在回答一个关于p < q
当p
和q
是指向不同对象/数组的指针时在C 中执行的未定义行为的问题。这让我想到:C ++ <
在这种情况下具有相同(未定义)的行为,但是还提供了标准库模板std::less
,该模板保证可以返回与<
可以比较指针时相同的东西,并在不能比较时返回一些一致的顺序。
C是否提供具有类似功能的东西,从而可以安全地比较任意指针(相同类型)?我尝试浏览C11标准并没有发现任何东西,但是我在C中的经验比在C ++中小得多,因此我很容易错过一些东西。
c pointers memory-model undefined-behavior memory-segmentation
下面是一个例子:
#include <cstddef>
#include <iostream>
struct A
{
char padding[7];
int x;
};
constexpr int offset = offsetof(A, x);
int main()
{
A a;
a.x = 42;
char *ptr = (char *)&a;
std::cout << *(int *)(ptr + offset) << '\n'; // Well-defined or not?
}
Run Code Online (Sandbox Code Playgroud)
我一直认为它是明确定义的(否则有什么意义offsetof
),但不确定。
最近有人告诉我它实际上是UB,所以我想一劳永逸地弄清楚。
上面的例子是否会导致UB?如果将类修改为非标准布局,是否会影响结果?
如果是 UB,是否有任何解决方法(例如申请std::launder
)?
整个主题似乎都没有实际意义且没有具体说明。
以下是我能找到的一些信息:
是否添加到“char *”指针 UB,当它实际上并不指向 char 数组时?- 2011 年,CWG 确认允许我们通过unsigned char
指针检查标准布局对象的表示。
char
可以使用指针代替,常识说它可以。不清楚是否std::launder
需要将来自 C++17 的凝视应用于转换的结果(unsigned char …
将类型T
为2D 的数组T*
强制转换为元素并取消引用元素是否安全?
由于二维数组的内存布局是线性的,因此基指针应该等于指向第一个元素的指针。由于它们指向的最终类型也是相同的,因此不应该存在任何对齐差异问题。
或者有一些方面会导致未定义的行为?
为了清楚起见,我的意思是这样的 -
int arr[10][10];
int p = *((int*) arr);
Run Code Online (Sandbox Code Playgroud)
另外,如果我访问第一个数组之外的元素,即 (int*) arr + 13,同样的问题。它是否属于越界访问的条款?因为我在第一个数组的边界之外访问。
我正在尝试使用将一个二维数组复制到另一个memcpy
。我的代码:
#include <stdio.h>
#include <string.h>
int print(int arr[][3], int n) {
for (int r = 0; r < 3; ++r) {
for (int c = 0; c < n; ++c)
printf("%d ", arr[r][c]);
printf("\n");
}
}
int main() {
int arr[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int arr_copy[3][3];
print(arr, 3);
memcpy(arr_copy, arr, 3);
print(arr_copy, 3);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
结果:
1 2 3
4 5 6
7 8 9
-1426063359 32726 -1902787872 …
Run Code Online (Sandbox Code Playgroud)