C语言中下述代码是否违反严格别名规则?
问题描述
下述代码是否违反C语言的严格别名规则?
#include <stdint.h> #include <stdio.h> #include <stdlib.h> int ialignment_of(double *p) { return (int)(((uintptr_t) p) % 16); } int main(void) { double _Complex * a = malloc(16*sizeof ( *a)); int alen = ialignment_of((void*)a); for (int i = 1; i < 8; ++i) { if ( ialignment_of((void*)(a+i)) == alen) { printf("pass\n"); break; } } free(a); }
我认为这段代码违反了严格别名规则,但FFTW库允许这样操作,这让我感到困惑。该函数在FFTW库的内核代码中针对实浮点指针定义,FFTW文档中提到我们可以进行指针转换(例如此处将double _Complex指针转换为double指针),文档原文及翻译如下:
Two arrays have equivalent alignment (for the purposes of applying a plan)
if and only if fftw_alignment_of returns the same value for the
corresponding pointers to their data (typecast to double* if necessary).
翻译:两个数组(对于执行计划而言)具有等效对齐的充要条件是,fftw_alignment_of对其数据的对应指针(必要时强制转换为double*)返回相同值。
解答
首先明确:这段代码并没有违反C语言的严格别名规则。
严格别名规则的核心是禁止通过不同类型的指针访问同一内存区域(例外情况包括char*、void*,或兼容类型、聚合体/共用体成员等)。但这段代码里的ialignment_of函数并没有通过传入的double*指针去访问内存中的数据——它只是把指针转换成uintptr_t类型计算对齐值,本质是对指针的数值做运算,完全没有触及指针指向的内存内容。
C标准允许任意对象指针与void*互相转换,也允许将对象指针转为足够大的整数类型(比如uintptr_t)再转换回来,只要转换前后的指针类型符合规则。这里的转换仅用于获取指针地址数值以计算对齐偏移,未涉及内存读写,因此不会触发严格别名规则的冲突。
FFTW文档允许将复数指针转为double*判断对齐,也是因为这种转换仅用于获取指针地址计算对齐,而非通过转换后的指针读写复数对象的内存。FFTW作为高性能数值库,依赖内存对齐优化运算,这种指针转换是安全的,完全没有违反严格别名规则的核心约束。
内容的提问来源于stack exchange,提问作者Aditya Kurrodu

