草庐IT

c++ - 表达式 "(ptr == 0) != (ptr == (void*)0)"真的可以吗?

coder 2023-05-02 原文

我在 a forum thread 中阅读了此声明链接到 in a comment by @jsantander :

Keep in mind that when you assign or compare a pointer to zero, there is some special magic that occurs behind the scenes to use the correct pattern for the given pointer (which may not actually be zero). This is one of the reasons why things like #define NULL (void*)0 are evil – if you compare a char* to NULL that magic has been explicitly (and probably unknowingly) turned off, and an invalid result may happen. Just to be extra clear:

(my_char_ptr == 0) != (my_char_ptr == (void*)0)

所以按照我的理解,对于 NULL 指针为 0xffff 的架构,代码 if (ptr) 会将 ptr 与 0xffff 而不是 0。

这是真的吗?它是由 C++ 标准描述的吗?

如果为真,则意味着即使对于具有非零 NULL 指针值的架构,也可以安全地使用 0。

编辑

作为额外的说明,请考虑以下代码:

char *ptr;
memset(&ptr, 0, sizeof(ptr));
if ((ptr == (void*)0) && (ptr != 0)) {
    printf("It can happen.\n");
}

这就是我理解此论坛帖子声明的方式。

最佳答案

您的问题分为两部分。我将从:

If true, it would mean that 0 can be safely used even for architectures that have a non-zero NULL pointer value.

你混淆了“值(value)”和“表现”。空指针的称为空指针值representation 是内存中用于存储此值的位。空指针的表示可以是任何东西,并不要求它是全位为零的。

在代码中:

char *p = 0;

p保证为空指针。它可能没有全为零。

这并不比代码更“神奇”:

float f = 5;

f没有与 int 5 相同的表示形式(内存中的位模式)可以,但没有问题。

C++ 标准对此进行了定义。文本在 C++11 中有所改变,增加了 nullptr。 ;但是在所有版本的 C 和 C++ 中,整数文字 0当转换为指针类型时会生成一个空指针。

来自 C++11:

A null pointer constant is an integral constant expression prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion.

0是一个空指针常量,并且(char *)0例如是 char * 类型的 空指针值 .

空指针是否全为零无关紧要。重要的是,当您转换值为 0 的整数 constexpr 时,保证会生成一个空指针。指向指针类型。

转到问题的另一部分。 你引用的文字完全是垃圾。正如我在上面讨论的那样,类型之间的转换会导致不同的表示形式这一想法没有“魔法”。

代码 my_char_ptr == NULL保证测试是否my_char_ptr是一个空指针。

如果你用自己的源代码编写,那将是邪恶的,#define NULL (void*)0 .这是因为定义任何可能由标准头文件定义的宏都是未定义的行为。

但是,标准 header 可以编写任何他们喜欢的内容,以便满足空指针的标准要求。编译器可以在标准头代码中“变魔术”;例如,不必有一个名为 iostream 的文件。在文件系统上;编译器可以看到 #include <iostream>然后硬编码标准要求的所有信息iostream发布。但是出于明显的实际原因,编译器通常不会这样做。它们允许独立团队开发标准库。

无论如何,如果 C++ 编译器包含 #define NULL (void *)0在它自己的头文件中,结果发生了一些不合格的事情,那么编译器显然是不合格的。如果没有任何不符合的情况发生,那么就没有问题。

我不知道您引用的文字会将其“邪恶”评论指向谁。如果它是针对编译器供应商告诉他们不要“邪恶”并淘汰不合格的编译器,我想我们无法反驳。

关于c++ - 表达式 "(ptr == 0) != (ptr == (void*)0)"真的可以吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22936924/

有关c++ - 表达式 "(ptr == 0) != (ptr == (void*)0)"真的可以吗?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  3. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  4. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  5. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  6. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  7. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  8. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  9. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  10. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

随机推荐