在C++中,我能否通过(unsigned) char*读取任何可读的有效内存位置?

7
今天我的搜索工具好像有点不太靠谱。我想知道在标准C++中是否能够通过一个(无符号的(?))char *来检查“任何”内存地址,其中“任何”是指程序内任何对象或数组(或其内部)。所以我想请问这种操作是否合法。
举个例子:
void passAnyObjectOrArrayOrSomethingElseValid(void* pObj) {
   unsigned char* pMemory = static_cast<unsigned char*>(pObj)
   MyTypeIdentifyier x = tryToFigureOutWhatThisIs(pMemory);
}

免责声明:这个问题纯粹是学术性质的,我并不打算将其用于生产代码!在“法律”方面,我指的是如果它确实符合标准,也就是说它能够在所有实现中都工作。 (不仅仅是在x86或一些常见硬件上。)

子问题:使用static_cast从void*地址获取char*指针是否正确?

3个回答

8

C++假设严格别名,这意味着根本不同类型的两个指针不引用相同的值。

但是,如bdonlan所正确指出的那样,标准为char和unsigned char指针做了一个例外。

因此,总的来说,对于任何指针类型来读取任何有意的地址(可能是任何类型),都是未定义的行为,但是对于问题中的unsigned char的特殊情况,它是允许的(ISO 14882:2003 3.10(15))。

static_cast进行编译时类型检查,因此很难总是有效。在这种情况下,您将需要reinterpret_cast。


2
这不是真的 - 任何提出更好主意的人都可以搜索 reinterpret_cast - 但他们搜不到 C 风格转换。此外,C 风格转换可能会变成更糟糕的转换而没有警告,例如 const_cast - Puppy
好的观点...能够对reinterpret_cast进行文本搜索是一个非常大的优点,我从未想过这一点。 - Damon
unsigned charchar可以与任何其他类型别名;请参见ISO/IEC 9899:1999(E) §6.5/7的最后一条以及脚注73。然而,出于其他原因传递任意地址(即不是从有效对象的地址获取的地址)是未定义的行为(§6.5.6/8、§6.5.3.2/4等)。 - bdonlan
1
请注意,9899:1999 是 C99 规范,而不是 C++。但由于 C++ 在语义方面尽量保持兼容性,因此它们可能是相同的。 - bdonlan
你说得对,那应该是ISO 14882:2003 3.10(15),我会更新答案。 - Damon
@Damon: q("static_cast 在编译时进行类型检查,因此它不太可能......") -- 既然我传递了一个 void*,那么 static_cast 没有什么可以检查的。这里的问题实际上是使用static_c还是reinterpret_c,由于我不需要任何转换将对象转换为指向 void 的指针(即 void* p = &object; 是有效的),所以我认为 static_creinterpret_c 更合适。显然,如果我直接将对象强制转换为 char 类型,则需要 reinterpret_c,因此这也可以成为在此处使用 reinterpret_c 的论据。 - Martin Ba

2
根据ISO/IEC 9899:1999 (E) §6.5/7规定,只有以下类型的lvalue表达式才能访问对象的存储值:与对象的有效类型兼容的类型、一些不相关的类型、字符类型。因此,在C中通过unsigned char解引用和检查(有效)指针是合法的。但是,您在那里发现的内容是未指定的;tryToFigureOutWhatThisIs没有明确定义的方法来确定它正在查看什么。我没有C++规范副本,但我怀疑它使用相同的定义以保持兼容性。

1
C++有类似的语言:“char或unsigned char类型”,而不是“字符类型”。 - Dennis Zickefoose

0
你只能使用 char*,而不能使用 unsigned char*。使用 unsigned char* 会违反严格别名规则并引发未定义的行为,但对于 char* 有一些例外。然而,尝试从读取的内存中实际执行任何操作是非常可疑的,并很可能导致某些未定义的行为。这就是为什么在惯用的C++代码中很少这样做的原因。

2
你确定吗?我记得无符号字符也适用于异常处理。不过我想我从来没有查过。 - jalf
@jalf:我很确定我看到了一个标准引用,它只说了 char* - Puppy
1
ISO/IEC 9899:1999 (E) §6.5/7 引用了“字符类型”,这允许有符号或无符号的访问。虽然它不是 C++ 规范,但很可能是相同的... - bdonlan
1
在C++03和C++11中,它肯定是charunsigned char。显然,即使char是有符号类型,signed char也不好。在C++03的3.10 [basic.lval]/15中,在C++11的3.10 [basic.lval]/10中。 - Dennis Zickefoose
@Dennis, @bdonlan:谢谢,非常有帮助。我之所以问是因为我不确定,所以很高兴看到相关的标准引用。 :) - jalf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接