Tag: 严格别名

通过void修改任何数据指针是否合法**

通过void **访问指针类型是否合法? 我已经查看了指针别名的标准引用,但我仍然不确定这是否是合法的C: int *array; void **vp = (void**)&array; *vp = malloc(sizeof(int)*10); 琐碎的例子,但它适用于我看到的更复杂的情况。 由于我通过类型不是int *或char *的变量访问int * ,所以它似乎不合法。 我不能就此得出一个简单的结论。 有关: C是否具有通用的“指针指针”类型? C-FAQ问题4.9

多维数组的别名

众所周知,2D数组是一个数组数组,标准要求它是一个连续分配的非空对象集 (6.2.5类型§20) – 这里的对象是一维数组。 众所周知,对于所有常见的实现,对于T arr2d[X][Y] ,以下等式是正确的,其中T是一个类型,X和Y的积分常数: (char *) &arr2d[i][j] == (char *) &arr2d[0][0] + i * Y * sizeof(T) + j * sizeof(T) 以上让我们认为可以允许对两个相同大小的二维数组和一维数组进行别名,或者甚至是另一个总大小相同的二维数组: 例如,以下程序编译并运行时没有警告,并给出预期输出: #include int main() { int i, j, k=0; int arr2d[3][4]; // array of 3 array of 4 ints int *arr1 = &arr2d[0][0]; // pointer to first element of an […]

C中“限制”的关键字相反?

由于严格别名可能有助于编译器更好地优化,因此C99引入了restrict关键字,如果程序员保证不会通过指向不同类型的指针访问它,则可以将其用作变量的限定符。 但是,由于多种原因,不同类型之间的类型转换是不可避免的,这将使编译器假设一个指针不是另一个指针的别名。 因此,变通方法是通过传递-fno-strict-aliasing (GCC标志)来禁用全局严格别名优化。 这完全没有意义,因为可能只有两个指针不应该完全优化。 因此,为什么不引入相反的restrict关键字,告诉编译器不要假设这两个指针指向不同的地址。 这有点类似于volatile所做的,并告诉编译器这个变量被大大改变,所以以特殊的方式对待它们。 是否可以创建这样的关键字? 编辑:有一种方法可以解决这个问题。 请参阅下面的yano评论。

严格别名和指向联合字段的指针

我有一个关于严格别名规则,工会和标准的问题。 假设我们有以下代码: #include union { int f1; short f2; } u = {0x1}; int * a = &u.f1; short * b = &u.f2; int main() { u.f1 = 1; *a += 1; u.f2 = 2; *b *= 2; printf( “%d %hd\n”, *a, *b); return 0; } 现在让我们来看看它是如何工作的: $ gcc-5.1.0-x86_64 tc -O3 -Wall && ./a.out 2 […]

这个严格的别名示例是否正确?

在过去一周左右的时间里,我一直在阅读严格的别名规则并进入本文: 了解C / C ++严格别名 。 本文通过几种方式将两个交换32位整数的两半进行交换,给出了良好的示例和违反严格别名规则的示例。 但是,我无法理解其中一个例子。 此代码被描述为已损坏。 uint32_t swaphalves(uint32_t a) { a = (a >> 16) | (a << 16); return a; } 给出的理由是: 这个版本看起来很合理,但你不知道|的左右两侧 每个人都会获得一个原始版本,或者如果其中一个获得另一个的结果。 这里没有序列点,因此我们对此处的操作顺序一无所知,并且您可能会使用不同级别的优化从同一编译器获得不同的结果。 我不同意。 这段代码对我来说很好看。 在a = (a >> 16 | (a << 16);行中只有一个写入a ,并且我希望在写入之前发生两次读取。此外,没有指针或引用,也没有不兼容的类型。 我在此代码中是否缺少严格的别名冲突,或者文章是否不正确?

在动态bool数组上使用memset是否定义明确?

在严格别名方面,这段代码是明确定义的行为吗? _Bool* array = malloc(n); memset(array, 0xFF, n); _Bool x = array[0]; 有效类型的规则有memcpy和memmove特殊情况(C176.5§6),但不适用于memset 。 我的看法是有效类型变为unsigned char 。 因为memset的第二个参数需要转换为unsigned char (C17 7.24.6.1),并且由于有效类型的规则,(C176.5§6): …或者被复制为字符类型数组,然后该访问的修改对象的有效类型以及不修改该值的后续访问是从中复制值的对象的有效类型,如果它有一个。 问题1:在memset调用之后, array存储的数据的有效类型是什么? 问题2: array[0]访问是否违反了严格的别名? 由于_Bool不是严格别名规则中排除的类型(与字符类型不同)。

任何编译器都通过memcpy / memmove传输有效类型

根据N1570 6.5 / 6: 如果使用memcpy或memmove将值复制到没有声明类型的对象中,或者将其复制为字符类型数组,则该访问的修改对象的有效类型以及不修改该值的后续访问的有效类型是复制值的对象的有效类型(如果有)。 这表明即使在“long”和其他整数类型具有相同表示的系统上,以下内容也会调用未定义的行为: #if ~0UL == ~0U #define long_equiv int #elif ~0UL == ~0ULL #define long_equiv long long #else #error Oops #endif long blah(void) { long l; long_equiv l2; long_equiv *p = malloc(sizeof (long)); l = 1234; memcpy(p, &l, sizeof (long)); l2 = *p; free(p); // Added to address complaint about leak […]

使用指向结构的别名数组,而不违反标准

阅读本文我理解你可以使用别名结构(不违反标准),如果它们具有兼容的成员,即给定以下结构: typedef struct { uint32_t a; uint32_t b; } Frizzly; 以下将破坏别名规则: uint32_t foo(uint16_t *i) { Frizzly *f = (Frizzly *)i; return f->a; } 但以下不会: uint32_t foo(uint32_t *i) { Frizzly *f = (Frizzly *)i; return f->b; } 因为所讨论的“聚合类型”包含与我们投入其中的指针兼容的类型,即类型为uint32_t的指针可以被转换为包含uint32_t类型的成员(或成员)的结构,而不会破坏别名规则。 首先,我是否理解正确? 其次,结构中(其他)变量的排序和类型是否重要? Frizzly说,如果Frizzly被定义如下: typedef struct { uint16_t b[2]; uint32_t a; } 在第二个示例中进行uint32_t , b现在由不兼容( uint32_t )类型的内存支持。 转换是否仍然有效(或者更确切地说,通过转换指针访问值)? 是否会改变i的第一个元素的值(另一种方式) […]

这个指针构建是否会破坏严格的别名规则?

这是Quake III Arena的快速反平方根实现: float Q_rsqrt( float number ) { long i; float x2, y; const float threehalfs = 1.5F; x2 = number * 0.5F; y = number; i = * ( long * ) &y; // evil floating point bit level hacking i = 0x5f3759df – ( i >> 1 ); // what? y = […]

一个对象可以有多个有效类型吗?

在ABI不向联合插入填充的平台上考虑以下代码: union { int xi; } x; x.xi = 1; 我相信第二行显示未定义的行为,因为它违反了严格的别名规则: x.xi引用的对象与x引用的对象是同一个对象。 两者都是相同的存储区域,术语对象在ISO 9899:2011§3.15中定义为: 宾语 执行环境中的1个数据存储区域,其内容可以表示值 2注意引用时,对象可能被解释为具有特定类型; 见6.3.2.1。 由于对象不仅仅是一个存储区域,我得出结论,由于x和x.xi占用相同的存储空间,因此它们是同一个对象。 x的有效类型是union { int xi; } 因为它是声明的类型。 见§6.5¶6: 6访问其存储值的对象的有效类型是对象的声明类型(如果有)。 87)如果通过具有非字符类型的左值的值将值存储到没有声明类型的对象中,则左值的类型将成为该访问的对象的有效类型以及后续访问的有效类型修改存储的值。 如果使用memcpy或memmove将值复制到没有声明类型的对象中,或者将其复制为字符类型数组,则该访问的修改对象的有效类型以及不修改该值的后续访问的有效类型是复制值的对象的有效类型(如果有)。 对于没有声明类型的对象的所有其他访问,对象的有效类型只是用于访问的左值的类型。 87)分配的对象没有声明的类型。 根据¶6的措辞,显然每个对象只能有一种有效类型。 在x.xi语句中,我通过lvalue x.xi typed int访问x 。 这不是§6.5¶7中列出的类型之一: 7对象的存储值只能由具有以下类型之一的左值表达式访问: 88) 与对象的有效类型兼容的类型, 与对象的有效类型兼容的类型的限定版本, 与对象的有效类型对应的有符号或无符号类型的类型, 与有效类型的对象的限定版本对应的有符号或无符号类型的类型, 在其成员中包含上述类型之一的聚合或联合类型(包括递归地,子聚合或包含联合的成员),或者 一个字符类型。 88)此列表的目的是指定对象可能或可能没有别名的情况。 因此,第二行表现出不确定的行为。 由于这种解释显然是错误的,我在哪里误读标准?