正在取消引用恒定的未定义行为

以下代码段当然不是一个好主意:

char *vram = (char*)0xB8000;
memset(vram,32,0x18000);

这不是:

volatile char *LCDC = (volatile char*)0xFF40;
char LCDCshadow = *LCDC;

以下显然是未定义的行为:

int *dontdoit = 0;
*dontdoit;

因为在指针上下文中使用0时,它将成为空指针的值,并且取消引用空指针是未定义的行为。

但是前两个示例是未定义行为还是仅仅是实施已定义/未指定
如果是后者,如何生成一个值为0的有效指针?

stkelvinlee 回答:正在取消引用恒定的未定义行为

具有0值的整数常量表达式转换为指针时,无论NULL指针的实际表示如何,都将产生NULL指针。

C standard的第6.3.2.3p3节规定:

  

整数常量表达式,其值为0,或者这样的整数   转换为类型void *的表达式称为空指针   不变。如果将空指针常量转换为指针类型,   结果指针(称为空指针)可以保证进行比较   不等于指向任何对象或函数的指针。

将任何其他整数值转换为指针值是定义的实现。从6.3.2.3p5节开始:

  

整数可以转换为任何指针类型。除了作为   先前指定的结果是实现定义的,可能   未正确对齐,可能未指向   引用的类型,并且可能是陷阱表示。

以上内容通常适用于需要访问特定内存地址的嵌入式实现。

如果您有一个支持非零NULL指针的实现,则可以通过变量将其赋值为0,例如:

int zero = 0;
int *zeroptr = (int *)zero;

在这种情况下,指针的值将为0,但不会为NULL。

,

将整数转换为指针是一种构造,大多数(但不是全部)实现都可以有意义地支持该构造。此外,该标准始终侧重于所有编译器需要支持的功能,而不是为大多数编译器应在实际中提供支持,并力求避免编译器根据其有意义地支持的功能接受或拒绝不同的语法结构。结果是,所有编译器都必须从语法上接受从整数到指针的转换,而不管它们是否将进行有意义的处理,但是标准并未描述任何有意义的情况。

即使在行为可能有意义的平台上,实现文档也不总是很清楚关于哪些构造是受支持的。考虑例如:

extern int x;
int test2(void)
{
    x=1;
    int res=*(int*)0x12345678;
    x=2;
    return res;
}

如果x是在程序集,链接器控制脚本或允许绝对放置的其他语言中定义的,则程序员可能会知道它将位于地址0x12345678。尽管使用上面的代码,当使用clang时,可能会允许从地址0x12345678进行volatile限定的读取可能与对x的首次写入发生交互,而gcc不会。 gcc的作者会认为标准不要求他们支持这种情况,因此任何需要这种支持的代码都被“破坏了”,但标准不要求编译器支持 any 有意义的结构涉及整数到指针的转换,而不是产生空指针的转换。

,
  

以下代码段当然不是一个好主意

是的,但这仅是因为它无法在符合标准的C编译器上进行编译。 char *vram = 0xB8000;甚至不是有效的C,并且像所有无效的C一样具有未定义的行为。参见"Pointer from integer/integer from pointer without a cast" issues

但是此代码很好:

char *vram = (char*)0xB8000;
memset(vram,32,0x18000);

发生的事情超出了C语言的范围。


volatile char *LCDC = 0xFF40;
char LCDCshadow = *LCDC;

同一错误,没有强制转换会导致此处的C无效。否则代码就完美了。


  

如果是后者,那么如何生成一个值为0的有效指针?

整数常量0或强制转换为void指针(void*)0的常量是一个特殊项目,称为 null指针常量。只要为指针分配了一个空指针常量,该指针就会转换为空指针。空指针的实际内容是实现定义的。遇到int* ptr = 0;之类的代码时,编译器可以为ptr提供对给定实现有意义的任何值-不一定是0

例如:

uint8_t data [sizeof(int*)];
int* ptr = 0;
memcpy(data,&ptr,sizeof(int*));

这不一定会导致data成为32位指针的00 00 00 00-它是实现定义的。

这是语言的设计方式,带有一些处理外来地址等的混淆意图。尽管在实践中,这意味着我们永远无法创建指向物理地址零的指针。因此,具有这种物理地址的系统-最值得注意的是几乎每个创建的单个微控制器系统-都不会像C那样对待空指针。因为他们需要使用物理地址0。这意味着在这样的系统上访问空指针将导致对地址0的访问。

在真实系统中,我遇到了一个错误,即偶然的空指针访问导致I / O端口处于活动状态,并且硬件因此而无法正常工作。

因此,可以归结为空指针是一种已知的语言设计错误。他们应该使用不能与地址null混淆的关键字0。 C ++试图在以后的标准中解决此问题,但C仍然无法解决。

本文链接:https://www.f2er.com/3120325.html

大家都在问