我一直以为C不接受NULL参数,直到我开始学习指针.在某些编程语言中,如python for one,可以将NULL参数作为参数传递,但在CI中始终认为这会导致未定义的行为.
我的问题只是一个好奇心,一个功能怎么可能,比如...
waitpid(child_pid, &status, options); //pointer &status
Run Code Online (Sandbox Code Playgroud)
...接受一个NULL指针作为参数而不会运行到未定义的行为,不是NULL指针只是指向什么?
简单地说,为什么这在C中可以接受?
据说在 C 中,当指针指向同一个数组或该数组末尾之后的一个元素时,算术和比较是明确定义的。那么数组第一个元素之前的一个呢?只要我不取消引用就可以了吗?
给定的
int a[10], *p;
p = a;
Run Code Online (Sandbox Code Playgroud)
(1) 写字合法--p吗?
(2)p-1在表达式中写入是否合法?
(3) 如果 (2) 没问题,我可以断言p-1 < a吗?
对此有一些实际的担忧。考虑一个reverse()函数,它反转以 结尾的 C 字符串'\0'。
#include <stdio.h>
void reverse(char *p)
{
char *b, t;
b = p;
while (*p != '\0')
p++;
if (p == b) /* Do I really need */
return; /* these two lines? */
for (p--; b < p; b++, p--)
t = *b, *b = *p, *p …Run Code Online (Sandbox Code Playgroud) 我将内存地址从double转换为整数.即使他们指向相同的地址,为什么值不同?
#include<iostream>
using namespace std;
int main()
{
double d = 2.5;
auto p = (int*)&d;
auto q = &d;
cout<<p<<endl; // prints memory address 0x7fff5fbff660
cout<<q<<endl; // print memory address 0x7fff5fbff660
cout<<*p<<endl; //prints 0
cout<<*q<<endl; // prints 2.5
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但为什么价值不同
0x7fff5fbff660
0x7fff5fbff660
0
2.5
Program ended with exit code: 0
Run Code Online (Sandbox Code Playgroud) 以下是现代C中未定义的行为:
union foo
{
int i;
float f;
};
union foo bar;
bar.f = 1.0f;
printf("%08x\n", bar.i);
Run Code Online (Sandbox Code Playgroud)
并打印1.0f的十六进制表示.
但是以下是未定义的行为:
int x;
printf("%08x\n", x);
Run Code Online (Sandbox Code Playgroud)
那这个呢?
union xyzzy
{
char c;
int i;
};
union xyzzy plugh;
Run Code Online (Sandbox Code Playgroud)
这应该是未定义的行为,因为没有plugh编写成员.
printf("%08x\n", plugh.i);
Run Code Online (Sandbox Code Playgroud)
但是这个呢.这是未定义的行为吗?
plugh.c = 'A';
printf("%08x\n", plugh.i);
Run Code Online (Sandbox Code Playgroud)
现在大多数C编译器都有sizeof(char) < sizeof(int),sizeof(int)或者是2或4.这意味着在这些情况下,最多plugh.i会写入50%或25%,但读取剩余的字节将读取未初始化的数据,因此应该是未定义的行为.在此基础上,是整个读取未定义的行为?
这是有效的 C++ 吗?
int main() {
int *p;
p = reinterpret_cast<int*>(42);
}
Run Code Online (Sandbox Code Playgroud)
假设我从不取消引用p.
查找 C++ 标准,我们有
C++17 §6.9.2/3 [basic.compound]
3指针类型的每个值都是以下之一:
- 指向对象或函数的指针(该指针被称为指向该对象或函数),或
- 超过对象末尾的指针 ([expr.add]),或
- 该类型的空指针值 ([conv.ptr]),或
- 无效的指针值。
指向或越过对象末尾的指针类型的值表示该对象占用的内存([intro.memory])中的第一个字节或存储结束后的内存中的第一个字节的地址分别被对象占用。[ 注意:超过对象结尾的指针 ([expr.add]) 不被认为指向可能位于该地址的对象类型的无关对象。指针值在它所表示的存储到达其存储持续时间的末尾时变为无效;参见 [basic.stc]。— 尾注 ] 出于指针算术 ([expr.add]) 和比较 ([expr.rel], [expr.eq]) 的目的,
p = reinterpret_cast<int*>(42);不适合可能值的列表。和:
C++17 §8.2.10/5 [expr.reinterpret.cast]
整数类型或枚举类型的值可以显式转换为指针。一个指针转换为一个足够大的整数(如果实现中存在这样的整数)并返回到相同的指针类型将具有其原始值;指针和整数之间的映射是由实现定义的。[ 注意:除了 6.7.4.3 中描述的那样,这种转换的结果不会是安全派生的指针值。— 尾注 ]
C++ 标准似乎没有更多地说明整数到指针的转换。查找 C17 标准:
C17 §6.3.2.3/5(强调我的)
整数可以转换为任何指针类型。除了前面指定的之外,结果是实现定义的,可能没有正确对齐,可能没有指向引用类型的实体,并且可能是陷阱表示0.68)
和
C17 §6.2.6.1/5
某些对象表示不需要表示对象类型的值。如果对象的存储值具有这样的表示形式并且被没有字符类型的左值表达式读取,则行为未定义。如果这种表示是由没有字符类型的左值表达式修改对象的全部或任何部分的副作用产生的,则行为是未定义的。50) 这种表示称为陷阱表示。
对我来说,似乎任何不符合 [basic.compound] 列表的值都是陷阱表示,因此p = reinterpret_cast<int*>(42);是 UB。我对么?还有其他东西使p = …
在读取值时,未定义行为(UB) 的一个明显示例是:
int a;
printf("%d\n", a);
Run Code Online (Sandbox Code Playgroud)
下面的例子呢?
int i = i; // `i` is not initialized when we are reading it by assigning it to itself.
int x; x = x; // Is this the same as above?
int y; int z = y;
Run Code Online (Sandbox Code Playgroud)
上面的三个例子都是 UB,还是有例外?
我想知道变量的初始化方式:
#include <stdio.h>
int main( void )
{
int ghosts[3];
for(int i =0 ; i < 3 ; i++)
printf("%d\n",ghosts[i]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这给我带来了随机值,例如 -12 2631 131 ..它们来自哪里?
例如,x86-64 Linux 上的 GCC:https ://godbolt.org/z/MooEE3ncc
我有一个猜测来回答我的问题,无论如何它都可能是错误的:
内存的寄存器在“清空”后获得 0 和 1 之间的随机电压,这些值“四舍五入”为 0 或 1,并且这些随机值取决于在某事上?!也许寄存器的制作方式?也许内存的容量会以某种方式发挥作用?甚至可能是温度?!!
这是Coursera的一个测验(未评分).问题是,以下代码可能评估的内容是什么?正确的答案是127和0(其他选项崩溃,-1,128.为什么以下代码可能评估为0?我理解为什么它会评估为127.它是否就像char字节未初始化一样简单因此随机?还可以评估0到127之间的任何#吗?
int foo(void) {
char bar[128];
char *baz = &bar[0];
baz[127] = 0;
return strlen(baz);
}
Run Code Online (Sandbox Code Playgroud) 在阅读本文时,我看到了一个我不了解的UB,希望您能澄清一下
size_t f(int x)
{
size_t a;
if(x) // either x nonzero or UB
a = 42;
return a;
}
Run Code Online (Sandbox Code Playgroud)
我猜UB是由于a没有初始化的值,但这不是它定义的行为吗?意思是,无论f(0)变量a是什么, 都将返回其所保存的值(我认为这类似于rand())。我们是否必须知道代码片段返回的值使代码具有明确定义的行为?