热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

为什么此声明取消引用编译器特定的类型标记指针警告?

如何解决《为什么此声明取消引用编译器特定的类型标记指针警告?》经验,为你挑选了3个好方法。

我已经阅读了 有关Stack Overflow RE的各种文章 :取消引用类型标记的指针错误。我的理解是,该错误本质上是编译器警告,它警告通过不同类型的指针访问对象的危险(尽管似乎为产生了例外),这是可以理解且合理的警告。 char*

我的问题特定于以下代码:为什么将指针的地址强制转换void**为此警告的合格字符(通过导致错误-Werror)?

而且,此代码针对多个目标体系结构进行了编译,只有其中一种会生成警告/错误-这是否暗示它合法地是特定于编译器版本的缺陷?

// main.c
#include 

typedef struct Foo
{
  int i;
} Foo;

void freeFunc( void** obj )
{
  if ( obj && * obj )
  {
    free( *obj );
    *obj = NULL;
  }
}

int main( int argc, char* argv[] )
{
  Foo* f = calloc( 1, sizeof( Foo ) );
  freeFunc( (void**)(&f) );

  return 0;
}

如果上述我的理解是正确的,a void**仍然只是一个指针,这应该是安全的。

没有不使用左值来解决此编译器特定警告/错误的解决方法?也就是说,我理解这以及为什么这可以解决问题,但是我想避免这种方法,因为我想利用freeFunc() NULL来实现预期的out-arg:

void* tmp = f;
freeFunc( &tmp );
f = NULL;

问题编译器(之一):

user@8d63f499ed92:/build$ /usr/local/crosstool/x86-fc3/bin/i686-fc3-linux-gnu-gcc --version && /usr/local/crosstool/x86-fc3/bin/i686-fc3-linux-gnu-gcc -Wall -O2 -Werror ./main.c
i686-fc3-linux-gnu-gcc (GCC) 3.4.5
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

./main.c: In function `main':
./main.c:21: warning: dereferencing type-punned pointer will break strict-aliasing rules

user@8d63f499ed92:/build$

不兼容的编译器(众多)之一:

user@8d63f499ed92:/build$ /usr/local/crosstool/x86-rh73/bin/i686-rh73-linux-gnu-gcc --version && /usr/local/crosstool/x86-rh73/bin/i686-rh73-linux-gnu-gcc -Wall -O2 -Werror ./main.c
i686-rh73-linux-gnu-gcc (GCC) 3.2.3
Copyright (C) 2002 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

user@8d63f499ed92:/build$

更新:我进一步发现警告似乎是专门在使用编译时生成的-O2(仍然仅使用注明的“问题编译器”)



1> Gilles 'SO- ..:

type的值void**是指向type的对象的指针void*。类型Foo*的对象不是类型的对象void*

类型和的之间存在隐式转换。此转换可能会更改值的表示形式。同样,您可以编写并且具有定义为value 的明确定义的行为,但是具有未定义的行为(实际上,在任何通用体系结构上都不会将其设置为“ pointer to ”)。Foo*void*int n = 3; double x = n;x3.0double *p = (double*)&n;p3.0

如今,不同类型的指向对象的指针具有不同表示形式的体系结构现在很少见,但C标准允许它们。有(稀有)旧机器,它们的单词指针是内存中一个单词的地址,而字节指针是一个单词的地址以及该单词的字节偏移量;在这种架构上,Foo*它将是一个字指针,并且void*将是一个字节指针。有(稀有)带有胖指针的机器,它们不仅包含有关对象地址的信息,而且还包含有关对象的类型,大小和访问控制列表的信息。指向确定类型的指针可能与void*在运行时需要其他类型信息的表示形式有所不同。

这种机器很少见,但C标准允许。一些C编译器利用此权限将类型标记的指针视为不同的指针来优化代码。指针混叠的风险是编译器优化代码能力的主要限制,因此编译器倾向于利用此类权限。

编译器可以自由地告诉您您做错了什么,或者悄悄地执行了您不需要的操作,或者悄悄地执行了您想要的操作。未定义的行为允许任何这些行为。

您可以创建freefunc一个宏:

#define FREE_SINGLE_REFERENCE(p) (free(p), (p) = NULL)

这带有宏的通常限制:缺乏类型安全性,p被评估两次。请注意,这仅是为了确保没有指针悬空时的安全性,前提p是指向释放对象的单个指针。



2> dbush..:

void *C标准特别对待A ,部分原因是A引用了不完整的类型。这种处理也延伸到void **,因为它确实指向一个完整的类型,特别是void *

严格的别名规则规定,您不能将一种类型的指针转​​换为另一种类型的指针,然后再取消对该指针的引用,因为这样做意味着将一种类型的字节重新解释为另一种字节。唯一的例外是在转换为允许您读取对象表示形式的字符类型时。

您可以通过使用类似于函数的宏而不是函数来解决此限制:

#define freeFunc(obj) (free(obj), (obj) = NULL)

您可以这样称呼:

freeFunc(f);

但是,这确实有一个局限性,因为上述宏将计算obj两次。如果您使用的是GCC,则可以通过一些扩展来避免这种情况,特别是typeof关键字和语句表达式:

#define freeFunc(obj) ({ typeof (&(obj)) ptr = &(obj); free(*ptr); *ptr = NULL; })


+1,用于更好地实现预期的行为。我看到的#define唯一的问题是它将两次评估obj。不过,我不知道避免这种第二次评估的好方法。即使使用语句表达式(GNU扩展名)也无法解决问题,因为使用完它的值后需要将其分配给obj。
@cmaster:如果您愿意使用GNU扩展(例如语句表达式),则可以使用[`typeof`](https://gcc.gnu.org/onlinedocs/gcc/Typeof.html)以避免评估`obj两次:`#define freeFunc(obj)({typeof(&(obj))ptr =&(obj); free(* ptr); * ptr = NULL;})`。

3> AProgrammer..:

取消引用类型查询指针是UB,您不能指望会发生什么。

不同的编译器会生成不同的警告,因此,可以将同一编译器的不同版本视为不同的编译器。对于您所看到的差异,这似乎比对体系结构的依赖性更好。

一个可以帮助您理解为什么类型修剪在这种情况下可能会很糟糕的情况是,您的函数不能在的架构上运行sizeof(Foo*) != sizeof(void*)。尽管我不知道这是真的,但是这是标准授权的。

一种解决方法是使用宏而不是函数。

请注意,它free接受空指针。


令人着迷的是`sizeof Foo *!= sizeof void *`。我从来没有遇到过“狂野”的指针大小依赖于类型的情况,因此多年来,我开始认为指针大小在给定的体系结构上都是相同的,这是理所当然的。
请注意,必须为typeof加上括号。
推荐阅读
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 电销机器人作为一种人工智能技术载体,可以帮助企业提升电销效率并节省人工成本。然而,电销机器人市场缺乏统一的市场准入标准,产品品质良莠不齐。创业者在代理或购买电销机器人时应注意谨防用录音冒充真人语音通话以及宣传技术与实际效果不符的情况。选择电销机器人时需要考察公司资质和产品品质,尤其要关注语音识别率。 ... [详细]
  • 如何去除Win7快捷方式的箭头
    本文介绍了如何去除Win7快捷方式的箭头的方法,通过生成一个透明的ico图标并将其命名为Empty.ico,将图标复制到windows目录下,并导入注册表,即可去除箭头。这样做可以改善默认快捷方式的外观,提升桌面整洁度。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
author-avatar
CY雪HLGC
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有