void *数组将元素转换为另一种类型

时间:2018-08-09 19:14:59

标签: c++ x86-64 data-conversion void-pointers

我有这样的东西:

void* a[] = {(void*)"Hello",(void*)1};
cout << (char*)a[0] << endl;
cout << (int)(int64_t)((int*)a[1]) << endl;

我如何简化行 (int)(int64_t)((int *)a [1])

是否可以将void *轻松更改为int?

2 个答案:

答案 0 :(得分:2)

void* a[] = {static_cast<void*>(const_cast<char*>("Hello")),reinterpret_cast<void*>(static_cast<omyptr_t>(1))};
std::cout << static_cast<char*>(a[0]) << std::endl;
std::cout << static_cast<int>(reinterpret_cast<intptr_t>(a[1])) << std::endl;

我认为这是所有定义的行为。

void*进行投射时,始终将其投射回完全相同的位置。避免使用原始C强制类型转换,因为它可以是静态的,const或重新解释强制类型转换,并且执行错误的操作确实可以破坏事情。

考虑使用std::anyboost::any代替原始void指针;或变体(如果您知道要存储的一组固定类型)。

答案 1 :(得分:0)

必须void*的数组吗? 您似乎应该只使用工会。

#include <cstdint>
#include <iostream>

union pointer_or_integer_t {
    void *vp;
    uintptr_t u;
    intptr_t i;
};

static_assert(sizeof(void *) == sizeof(pointer_or_integer_t),
              "intptr_t or uintptr_t are larger than the size as a pointer");

int main() {
    pointer_or_integer_t a[] = {(void*)"Hello", {.i = 1}};

    std::cout << (const char*)a[0].vp << '\n';
    std::cout << a[1].i << '\n';
}

(除非您确实要强制刷新,否则请勿使用std::endl。)

这将编译为可以完成我们想要的代码,而没有额外的开销on the Godbolt compiler explorer

请注意,C ++中的{.i = 1}指定初始化程序目前是GNU扩展,但将成为C ++ 20的一部分。 g ++ 8.2 -pedantic警告:

<source>:15:50: warning: C++ designated initializers only available with -std=c++2a or -std=gnu++2a [-Wpedantic]

     pointer_or_integer_t a[] = {(void*)"Hello", {.i = 1}};
                                              ^

您也可以使用void []uintptr_t[]的并集,但这只有在知道大小的情况下才能轻松实现。使每个数组元素具有自己的联合效果更好。

我认为使用强制转换(而不是void*)将联合数组转换为memcpyvoid **数组仍然是UB,即使您使用asserts来检查它具有相同的布局。

但是,如果您有一个仅允许您传递pointer_or_integer_t **的接口,则可以在接收函数中将其投射回void **。如果没有代码实际索引void **,就根本没有UB。

在实践中,如果某事物确实像void*那样索引到对象中,通常没有问题,因为您的联合具有与android { // more configurations flavorDimensions "project", "environment" productFlavors { basic { dimension "project" } advanced { dimension "project" } flavorDevelopment { dimension "environment" applicationId "ch.myproject.app.development" } flavorTest { dimension "environment" applicationId "ch.myproject.app.test" } flavorIntegration { dimension "environment" applicationId "ch.myproject.app.integration" } flavorProduction { dimension "environment" applicationId "ch.myproject.app.production" } buildTypes { debug { testCoverageEnabled = true minifyEnabled = false shrinkResources = false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debugInstantRun.initWith(buildTypes.debug) debugInstantRun { // we are changing this build variant later on runtime, so that it will use constant values // for versionCode and versionName in the Manifest, for make sure the // manifest is unchanged between the instantRun builds // Specifies a sorted list of fallback build types that the // plugin should try to use when a dependency does not include a // "debugInstantRun" build type. You may specify as many fallbacks as you // like, and the plugin selects the first build type that's // available in the dependency. matchingFallbacks = ['debug'] } release { // Currently all environments (dev/test/int/prod) are signed by the Production certificates minifyEnabled = false shrinkResources = false } } // more configurations } // end of android 数组相同的对象表示形式。