Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 这是否违反了严格的别名规则?_C_Gcc_C99_Type Punning - Fatal编程技术网

C 这是否违反了严格的别名规则?

C 这是否违反了严格的别名规则?,c,gcc,c99,type-punning,C,Gcc,C99,Type Punning,考虑以下C代码: extern void CheckIfPtrInHeap( void* p ); void TakePtr( void** p, size_t n ) { for( size_t i = 0 ; i < n ; ++i ) CheckIfPtrInHeap( p[ i ] ); } typedef size_t val_t[ 6 ]; extern void* stack_top; void Func() { val_t val; TakePt

考虑以下C代码:

extern void CheckIfPtrInHeap( void* p );

void TakePtr( void** p, size_t n )
{
  for( size_t i = 0 ; i < n ; ++i )
    CheckIfPtrInHeap( p[ i ] );
}

typedef size_t val_t[ 6 ];
extern void* stack_top;

void Func()
{
  val_t val;

  TakePtr( (void**) &val, ( (size_t) stack_top - (size_t) &val ) / sizof( size_t ) );
}

甚至

void** ptr = (void**) (void*) &val;
或者(告诉编译器‘嘿,我知道我在做什么’,至少如果我正确理解了
restrict


严格的别名规则只不过是这样一个事实:通过另一种类型的左值访问一种类型的对象是非法的(诸如
void*
char*
以及其他明显的情况除外)。不多也不少

仅仅有两个、三个或10000个指针同时指向同一个对象,不管它们是否都是同一类型,与严格的别名规则无关。您需要取消对其中一个的引用,才能发生冲突

这也与
restrict
关键字完全无关,该关键字与类型无关,只是通知编译器指针是唯一的

无论使用第二个参数玩什么游戏,
TakePtr
都是违反规则的,这仅仅是因为它访问一个
size\t
数组,就好像它是一个
void*
数组一样

联合不会有帮助,因为分配给联合的一个字段,然后访问另一类型的字段也是不合法的。在这种情况下,也会发生与取消引用错误指针时完全相同的坏事


通过不同类型的左值访问值的唯一半正确方法是通过
memcpy
。并不是说结果是自动定义好的。表示类型A的有效值的位模式可能不表示类型B的有效值。但如果不是这种情况,则可以将其memcpy,并保证提供正确的值。

这取决于
TakePtr()
的具体操作。为什么要将指针投射到
大小\u t
?正确的强制转换为
uintptr\t
TakePtr()
对它的参数有什么作用?@FilipeGonçalves在实际的代码
TakePtr
中标记并清除垃圾收集,因此它以指向堆栈的指针为例,长度-这只是要复制的代码,实际的函数采用类似
(size_t)stack_top-(size_t)的值&vals
它是否曾经取消引用指针?@FilipeGonçalves请参见编辑,添加了一个更完整的TakePtrWell实现,可以稍微清除一些内容-那么这是否意味着编译器发出有关强制转换的警告非常正确?一个合适的解决方案是让TakePtr使用大小作为参数?不,请不要
size\t**
size\u t**
指向类型为
size\u t*
的对象。您没有可以指向的
size.*
类型的对象。您有一个
大小\u t
数组。使用
size\u t*
访问它。我实际上拥有的是一块内存,我知道它包含指针,但无法知道它们指向什么,因为它们是使用某种形式的malloc获得的。问题是,这段内存碰巧以size\u t数组的形式传递给我(实际上可能不是size\u t,而是一个整数,它被引导为具有与指针相同的大小),我无法更改它..因此,您以
size\u t
数组的形式传递给您。在上帝的绿色地球上,是什么让你试图通过
size\t**
类型的指针访问它?顺便说一句,你有一个指针数组被双关到一个整数数组,这意味着已经违反了别名规则,现在担心有点晚了。
void* p1 = (void*) &val;
void** ptr = &p1;
void** ptr = (void**) (void*) &val;
void* restrict p1 = (void*) &val;
void** ptr = &p1;
val_t* p1 = &val;
void** p2 = NULL;
memcpy( p2, p1, sizeof( p1 ) );