void foo (const std::string &s) {}
int main() {
foo(0); //compiles, but invariably causes runtime error
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译器(g ++ 4.4)显然通过调用来解释0为char* NULL和构造.这当然没用,因为指针不是指向c-string的有效指针.当我尝试调用时,这种误解不会出现,这有助于产生编译时错误.sstring::string(const char*, const Allocator &a = Allocator())NULLfoo(1)
当我不小心调用类似的函数时,是否有可能在编译时得到这样的错误或警告
void bar(const std::string &s, int i=1);
Run Code Online (Sandbox Code Playgroud)
与bar(0),忘记了string,实际上有意义i=0?
它看起来像下面的程序计算一个无效的指针,因为NULL除了赋值和比较相等之外没有任何好处:
#include <stdlib.h>
#include <stdio.h>
int main() {
char *c = NULL;
c--;
printf("c: %p\n", c);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然而,似乎GCC或Clang针对未定义行为的警告或工具都没有说这实际上是UB.这个算术实际上是否有效,而且我太迂腐了,或者这是我们应该报告的检查机制的缺陷吗?
测试:
$ clang-3.3 -Weverything -g -O0 -fsanitize=undefined -fsanitize=null -fsanitize=address offsetnull.c -o offsetnull
$ ./offsetnull
c: 0xffffffffffffffff
$ gcc-4.8 -g -O0 -fsanitize=address offsetnull.c -o offsetnull
$ ./offsetnull
c: 0xffffffffffffffff
Run Code Online (Sandbox Code Playgroud)
似乎很好地记录了Clang和GCC使用的AddressSanitizer更侧重于解除坏指针的引用,所以这很公平.但其他检查也没有抓住它: - /
编辑:我问这个问题的部分原因是-fsanitize标志能够动态检查生成的代码中的良好定义.这是他们应该抓住的东西吗?
这可以被认为是这个问题的扩展(我只对C感兴趣,但添加C++来完成扩展)
6.3.2.3.3中的C11标准说:
值为0的整型常量表达式或此类表达式转换为类型
void *称为空指针常量.
我个人对此的看法是0并且(void *)0表示空指针,其整数值实际上可能不是0,但是不包括0强制转换为任何其他类型.
但是,标准然后继续:
如果将空指针常量转换为指针类型,则生成的指针称为空指针,...
它包含(int *)0为空指针,因为强制转换是一种显式转换(C11,6.3),它在转换方法下列出.
然而,令我惊讶的是以下短语
...或者这样的表达式转换为
void *...
有了上面的语义,这句话似乎完全没用.问题是,这句话完全没用吗?如果没有,它有什么影响?因此,是否(int *)0为空指针?
另一个可以帮助讨论的问题如下.被(long long)123视为"123转换为long long",或"123与类型long long".换句话说,有没有转换(long long)123?如果没有,则上面的第二个引用不包括(int *)0为空指针.
来自 C17 草案 (6.3.2.3 \xc2\xb63):
\n\n\n值为 0 的整型常量表达式,或此类转换为类型的表达式
\nvoid *,称为空指针常量。67)如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与任何对象或函数的指针比较不相等。67)该宏
\nNULL在(和其他标头)中定义<stddef.h>为空指针常量 [...]。
由此可见,以下是空指针常量:0, 0UL, (void *)0, (void *)0UL, NULL。
进一步得出以下是空指针:(int *)0, (int *)0UL, (int *)(void *)0, (int *)(void *)0UL, (int *)NULL。有趣的是,这些都不是“空指针常量”;看这里。
以下空指针常量是空指针(因为void *是指针类型,并且0和0UL是空指针常量):(void *)0 …
标准说,取消引用空指针会导致未定义的行为.但是什么是"空指针"?在下面的代码中,我们称之为"空指针":
struct X
{
static X* get() { return reinterpret_cast<X*>(1); }
void f() { }
};
int main()
{
X* x = 0;
(*x).f(); // the null pointer? (1)
x = X::get();
(*x).f(); // the null pointer? (2)
x = reinterpret_cast<X*>( X::get() - X::get() );
(*x).f(); // the null pointer? (3)
(*(X*)0).f(); // I think that this the only null pointer here (4)
}
Run Code Online (Sandbox Code Playgroud)
我的想法是,只有在最后一种情况下才会取消引用空指针.我对吗?根据C++标准,编译时空指针和运行时之间是否存在差异?
我目前正在阅读一本关于C++的书,在本书中,作者解释说使用常量而不是NULL宏更好,但没有真正解释为什么或给出任何优点或缺点.
那么为什么最好使用:
const int NULL = 0;
int *ptr = NULL;
Run Code Online (Sandbox Code Playgroud)
代替:
int *ptr = NULL;
Run Code Online (Sandbox Code Playgroud)
唯一的解释是NULL宏不是类型安全的.
首先,我已经看到了关于C99的这个问题,并且接受的答案参考操作数未在C99标准草案中评估.我不确定这个答案是否适用于C++ 03.还有一个关于C++的问题,引用了类似措辞的答案,并且在某些情况下,还会出现未评估的操作数.未评估未评估的操作数.措辞.
我有这个代码:
int* ptr = 0;
void* buffer = malloc( 10 * sizeof( *ptr ) );
Run Code Online (Sandbox Code Playgroud)
问题是 - 里面是否有空指针取消引用(以及UB)sizeof()?
C++ 03 5.3.3/1表示sizeof运算符产生其操作数的对象表示中的字节数.操作数是表达式(未计算)或带括号的type-id.
链接到答案引用这个或类似的措辞,并使用"未评估"部分推断出没有UB.
但是,在这种情况下,我无法找到标准链接评估的确切位置与是否具有UB.
"不评估"应用sizeof的表达式使得在C++中取消引用sizeof中的null或无效指针是合法的吗?
int& fun()
{
int * temp = NULL;
return *temp;
}
Run Code Online (Sandbox Code Playgroud)
在上面的方法中,我试图取消引用NULL指针.当我调用此函数时,它不会给出异常.我发现当返回类型是引用时它不会给出异常,如果它是按值,那么它.即使将NULL指针的解引用引用为引用(如下面的行),它也不会给出.
int* temp = NULL:
int& temp1 = *temp;
Run Code Online (Sandbox Code Playgroud)
在这里我的问题是,在引用的情况下编译器是否进行解除引用?
我重写了onCreateDialog和onPrepareDialog方法或Dialog类.
我按照Reto Meier的专业Android应用程序开发书第5章中的示例来提取一些XML数据,然后使用对话框显示信息.
我基本上完全遵循了它,但更改了变量以适合我自己的XML模式,如下所示:
@Override
public Dialog onCreateDialog(int id) {
switch(id) {
case (SETTINGS_DIALOG) :
LayoutInflater li = LayoutInflater.from(this);
View settingsDetailsView = li.inflate(R.layout.details, null);
AlertDialog.Builder settingsDialog = new AlertDialog.Builder(this);
settingsDialog.setTitle("Provisioned Settings");
settingsDialog.setView(settingsDetailsView);
return settingsDialog.create();
}
return null;
}
@Override
public void onPrepareDialog(int id, Dialog dialog) {
switch(id) {
case (SETTINGS_DIALOG) :
String afpunText = " ";
if(setting.getAddForPublicUserNames() == 1){
afpunText = "Yes";
}
else{
afpunText = "No";
}
String Text = "Login Settings: " + "\n"
+ "Password: " + …Run Code Online (Sandbox Code Playgroud) 我已经编写 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 的不兼容性?