我已经编写 C++ 多年,nullptr用于空指针。我也知道 C,从那里 NULL 起源,并记住它是一个空指针的常量,类型void *。
出于NULL某些原因,我不得不在我的 C++ 代码中使用某些东西。好吧,想象一下当在一些模板参数推导过程中编译器告诉我我的 NULL 真的是一个......长时我的惊讶。所以,我仔细检查了:
#include <type_traits>
#include <cstddef>
static_assert(not std::is_same<decltype(NULL), long>::value, "NULL is long ???");
Run Code Online (Sandbox Code Playgroud)
事实上,静态断言失败(使用 GCC 和 clang)。
在cppreference.com 上检查,果然(C++11 措辞):
宏 NULL 是一个实现定义的空指针常量,它可以是一个值为 0 的整数文字,或者一个类型为 的纯右值
std::nullptr_t。
为什么这是有道理的?就其本身而言,鉴于 C 的不兼容性?
测试C#中的引用类型变量是否为空指针(如if (x == null)...)与测试小于零的整数甚至bool为假的性能有何关系?
是否有关于此类空指针测试的其他问题,例如是否生成了garbadge?
我为游戏的每一帧做了数百次这些测试,我想知道这些是否会导致问题或者能否更有效地实施?
在C89/C99 +中使用NULL优先于0是否有"硬"原因,并且在不考虑与标准符合性相关的深层关注的情况下进行交换,即使在使用C的非常模糊的方面的代码中也是如此.
我关注标准合规性,可移植性,未定义的行为,与语言的意外角落的意外不同的交互等"硬"事物,(假设的)Milliard Gargantubrain分段记忆超级计算机是否可能释放其魔法烟雾等,如果你替换一个为了另一个.
在这个网站上已经有一个关于C++的类似问题,但我不关心C++.我相信这是C++行为可能与C不同的领域之一.
风格和意图的问题虽然很重要,但并不认为在问答论坛中讨论它们是主题性的或有用的.
我和其他人发现的答案主要涉及测试和分配(我们通常会看到,并且可以互换使用它们是安全的).我问是否有任何想法需要采取你已经找到的任意奇怪但符合标准的代码,并在语法上将NULL替换为0(或者当0是指针时可能反之亦然),无论是否是做风格的明智之举.很难给出意想不到的交互的例外,但是,例如,功能指针经常会把我们赶出去,也许是尺寸,....
我已经阅读了描述0和NULL如何表现的相关标准部分,有人可以帮助我在不明显的情况下对指针常量0和NULL的交换产生影响吗?或者向我保证没有.
我无法弄清楚我是否做过愚蠢的事情,或者我是否在gorm中发现了一个错误.虽然我非常清楚"无效的内存地址或无指针取消引用"是什么意思,但我对它出现在这里的原因完全不知所措.
简而言之,我打电话给db.First()我,我没有明显的理由感到恐慌.
我的代码的相关部分:
package main
import (
"fmt"
"github.com/gorilla/mux"
"github.com/jinzhu/gorm"
"net/http"
"os"
)
type message struct {
gorm.Model
Title string
Body string `sql:"size:0"` // blob
}
var db = gorm.DB{} // garbage
func messageHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
m := message{}
query := db.First(&m, vars["id"])
if query.Error != nil {
if query.Error == gorm.RecordNotFound {
notFoundHandler(w, r)
return
} else {
fmt.Fprintf(os.Stderr, "database query failed: %v", query.Error)
internalServerErrorHandler(w, r)
return
}
}
// actually do …Run Code Online (Sandbox Code Playgroud) 我有一个非常古老的(和巨大的)Win32项目,该项目使用NULL指针进行大量检查,通过强制转换为指向解除引用的指针.像这样:
int* x = NULL; //somewhere
//... code
if (NULL == &(*(int*)x) //somewhere else
return;
Run Code Online (Sandbox Code Playgroud)
是的,我知道这段代码很愚蠢,需要重构.但由于代码量很大,这是不可能的.现在我需要在Xcode的MacOS Sierra下编译这个项目,这会导致很大的问题......事实证明,在发布模式下(使用代码优化),条件以不正确的行为执行(因为解除引用NULL而被称为未定义的行为指针).
根据GCC的这个文档,有一个选项-fno-delete-null-pointer-checks,但是当启用O1,O2或O3优化时,它似乎不适用于LLVM.所以问题是:如何强制LLVM 8.0编译器允许这样的解引用?
UPDATE.检查问题的真实工作示例.
//somewhere 1
class carr
{
public:
carr(int length)
{
xarr = new void*[length];
for (int i = 0; i < length; i++)
xarr[i] = NULL;
}
//some other fields and methods
void** xarr;
int& operator[](int i)
{
return *(int*)xarr[i];
}
};
//somewhere 2
carr m(5);
bool something(int i)
{
int* el = &m[i]; …Run Code Online (Sandbox Code Playgroud) 我一直听到人们谈论非可空引用类型将如何解决如此多的错误并使编程变得更加容易.即使是null的创建者也称它为十亿美元的错误,而Spec#引入了非可空类型来解决这个问题.
编辑:忽略我对Spec#的评论.我误解了它是如何工作的.
编辑2:我必须和错误的人交谈,我真的希望有人能够与之争辩:-)
所以我猜想,在少数人中,我错了,但我不明白为什么这场辩论有任何优点.我认为null是一个bug查找工具.考虑以下:
class Class { ... }
void main() {
Class c = nullptr;
// ... ... ... code ...
for(int i = 0; i < c.count; ++i) { ... }
}
Run Code Online (Sandbox Code Playgroud)
BAM!访问冲突.有人忘了初始化c.
现在考虑一下:
class Class { ... }
void main() {
Class c = new Class(); // set to new Class() by default
// ... ... ... code ...
for(int i = 0; i < c.count; ++i) { ... …Run Code Online (Sandbox Code Playgroud) 而不是通常if (myString == null || myString.equals(""))我倾向于使用org.apache.commons.lang.StringUtils类和做if (StringUtils.isEmpty(myString)).
然而,这 - 至少我正在做的方式 - 带来了巨大的缺点:因为FindBugs - 或编译器警告机制,f.恩.来自Eclipse - 将不再看到显式的空检查,它将不再被myString视为可能为null,因此它将不再引发关于它的潜在(或确定)空指针的警告,并且这些警告在我的视图中非常有用.
示例(已添加):
import org.apache.commons.lang.StringUtils;
public class TestWarning
{
void testWarning(String myString)
{
//if (myString == null || myString.equals("")) // With this, the last line shows the warning.
if (StringUtils.isEmpty(myString)) // With this, no warning.
{
// Anything.
}
int x = myString.length(); // Warning is here: "Potential null pointer access: The variable myString may be null at …Run Code Online (Sandbox Code Playgroud) 使用std::shared_ptr表达共享所有权和可选性(可能为null).
我发现自己处于只想在代码中表达共享所有权的情况,而且没有选择性.当使用a shared_ptr作为函数参数时,我必须让函数检查它是否为null以保持一致/安全.
在许多情况下,传递引用而不是当然是一种选择,但我有时也希望转移所有权,因为它可以使用shared_ptr.
是否有一个类可以替换shared_ptr而没有可能为null,一些常规来处理这个问题,或者我的问题没有多大意义?
我最近向std::string构造函数传递了一个空指针并得到了未定义的行为。我敢肯定,这是在我之前成千上万的程序员所做的事情,同样的错误无疑已经导致无数程序崩溃。使用代码转换时谈到了很多char*使用代码std::string,它的那种东西,是不是在编译时开捕,并可以很容易地在运行时的单元测试错过。
我感到困惑的是指定std::string这种方式的原因。
为什么不直接定义std::string(NULL)==""?
效率损失可以忽略不计,我怀疑它在实际程序中甚至可以测量。
有谁知道std::string(NULL)未定义的可能原因是什么?
Richard Reese所著的《理解和使用 C 指针》一书说:
空概念是空指针常量支持的抽象。这个常数可能是也可能不是一个常数零。AC 程序员不需要关心他们实际的内部表示。
我的问题是,由于“这个常数可能是也可能不是常数零”,我在我的代码中执行以下操作是否安全:
int *ptr = NULL;
// Some code which probably sets ptr to a valid memory address
if(!ptr)
{
ERROR();
}
Run Code Online (Sandbox Code Playgroud)
如果 NULL 不为 0,则 if 子句有可能评估为真。
null-pointer ×10
c++ ×4
c ×3
null ×3
c# ×1
c#-4.0 ×1
clang++ ×1
d ×1
dereference ×1
findbugs ×1
go ×1
go-gorm ×1
invariants ×1
java ×1
non-nullable ×1
nullptr ×1
performance ×1
pointers ×1
std ×1
string ×1