如果我有:
unsigned int x;
x -= x;
Run Code Online (Sandbox Code Playgroud)
很明显,x 应该这样表达后是零,但到处看,他们说的行为,这种代码是不确定的,而不是仅仅值x(直到减法之前).
两个问题:
这段代码的行为确实未定义吗?
(例如,代码在兼容系统上崩溃[或更糟]?)
如果是这样,为什么 C表示行为是未定义的,当非常清楚x这里应该为零时?
即不在此定义行为给出的优势是什么?
很明显,编译器可以简单地使用它在变量中认为"方便"的任何垃圾值,并且它可以按预期工作......这种方法有什么问题?
在编写项目时,我遇到了一个奇怪的问题.
这是我设法编写的用于重新创建问题的最小代码.我故意将一个实际的字符串存储在其他地方,并分配了足够的空间.
// #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stddef.h> // For offsetof()
typedef struct _pack{
// The type of `c` doesn't matter as long as it's inside of a struct.
int64_t c;
} pack;
int main(){
pack *p;
char str[9] = "aaaaaaaa"; // Input
size_t len = offsetof(pack, c) + (strlen(str) + 1);
p = malloc(len);
// Version 1: crash
strcpy((char*)&(p->c), str);
// Version 2: crash
strncpy((char*)&(p->c), str, strlen(str)+1);
// Version 3: works!
memcpy((char*)&(p->c), str, strlen(str)+1); …Run Code Online (Sandbox Code Playgroud) 我正在阅读Pointer Arithmetic中的一些内容,我遇到了两件我无法理解的事情,也不知道它的用途
address_expression - address_expression
Run Code Online (Sandbox Code Playgroud)
并且
address_expression > address_expression
Run Code Online (Sandbox Code Playgroud)
有人可以向我解释一下,它们是如何工作的以及何时使用它们.
编辑:
我想说的是,如果我只取两个地址并减去它们,它们会产生什么
如果我拿两个地址并比较它们的结果或基于的比较
编辑:我现在明白了减去地址的结果,但比较地址我仍然没有得到它.
我理解1 <2,但是地址如何比另一个更大,他们在比较什么
在这两个示例中,通过偏移指向其他成员的指针来访问结构的成员是否会导致未定义/未指定/实现定义的行为?
struct {
int a;
int b;
} foo1 = {0, 0};
(&foo1.a)[1] = 1;
printf("%d", foo1.b);
struct {
int arr[1];
int b;
} foo2 = {{0}, 0};
foo2.arr[1] = 1;
printf("%d", foo2.b);
Run Code Online (Sandbox Code Playgroud)
第6.7.2.1段第14段似乎表明这应该是实施定义的:
结构或联合对象的每个非位字段成员以适合其类型的实现定义方式对齐.
然后继续说:
结构对象中可能存在未命名的填充,但不是在其开头.
但是,像下面这样的代码似乎很常见:
union {
int arr[2];
struct {
int a;
int b;
};
} foo3 = {{0, 0}};
foo3.arr[1] = 1;
printf("%d", foo3.b);
(&foo3.a)[1] = 2; // appears to be illegal despite foo3.arr == &foo3.a
printf("%d", foo3.b);
Run Code Online (Sandbox Code Playgroud)
标准似乎保证foo3.arr是相同的&foo3.a,并且没有任何意义,指的是一种方式是合法的而另一种方式不是,但同样没有意义的是,添加外部联合与数组应该突然(&foo3.a)[1]法律. …
结构中相同类型的连续成员之间的指针算术过去常常是一种常见的做法,而指针算术仅在数组内有效.在C++中,它将是明确的Undefined Behavior,因为数组只能由声明或新表达式创建.但是C语言将数组定义为具有特定成员对象类型的连续分配的非空对象集,称为元素类型.(n1570 C11草案,6.2.5类型§20).因此,如果我们可以确保成员是连续的(意味着它们之间没有填充),那么将其视为数组是合法的.
这是一个简化的示例,它在没有警告的情况下编译,并在运行时给出预期的结果:
#include <stdio.h>
#include <stddef.h>
#include <assert.h>
struct quad {
int x;
int y;
int z;
int t;
};
int main() {
// ensure members are consecutive (note 1)
static_assert(offsetof(struct quad, t) == 3 * sizeof(int),
"unexpected padding in quad struct");
struct quad q;
int *ix = &q.x;
for(int i=0; i<4; i++) {
ix[i] = i;
}
printf("Quad: %d %d %d %d\n", q.x, q.y, q.z, q.t);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它在这里没有意义,但我已经看到了真实世界的例子,在结构的成员之间进行迭代允许更简单的代码,而错误的风险更低.
题:
在上面的例子中,是否static_assert足以使用数组合法化结构的别名?
(注释1)由于结构 …