sizeof(int) == sizeof(void*)?

发布于 2024-07-13 10:37:32 字数 39 浏览 2 评论 0原文

是否存在与指针大小相同的整数类型? 在所有微架构上都有保证吗?

Is there an integer type with the same size as pointer? Guaranteed on all microarchitectures?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

流年已逝 2024-07-20 10:37:32

根据 此维基百科页面,在 C99 中,您的 stdint.h 标头可能声明 intptr_t 和 uintptr_t,但是这当然需要

  • C99
  • 编译器实现者选择实现标准的这个可选部分

所以总的来说,我认为这很难。

According to this Wikipedia page, in C99 your stdint.h header might declare intptr_t and uintptr_t, but then that of course requires

  • C99
  • A compiler implementor which has chosen to implement this optional part of the standard

So in general I think this one is tough.

辞取 2024-07-20 10:37:32

简单地说,不。 不保证在所有架构上。

我的问题是:为什么? 如果您想分配一个足够大的类型来存储 void*,最好的分配方式是(令人惊讶的是:-)一个 void*。 为什么需要将其放入 int 中?

编辑:根据您对重复问题的评论,您想要存储指针的特殊值 (1,2,3) 以指示额外信息。

不!! 不要这样做!!。 无法保证 1、2 和 3 不是完全有效的指针。 在需要在 4 字节边界上对齐指针的系统中可能会出现这种情况,但是,由于您询问了所有体系结构,我假设您具有较高的可移植性价值。

寻找另一种正确的方法。 例如,使用 union(记忆中的语法,可能是错误的):

typedef struct {
    int isPointer;
    union {
        int intVal;
        void *ptrVal;
    }
} myType;

然后您可以使用 isPointer 'boolean' 来决定是否应该将 union 视为整数或指针。

编辑:

如果执行速度是最重要的,那么 typedef 解决方案就是最佳选择。 基本上,您必须为要运行的每个平台定义所需的整数。 您可以通过条件编译来做到这一点。 我还会添加运行时检查,以确保您已正确编译每个平台(我在源代码中定义它,但您会将其作为编译器标志传递,例如“cc -DPTRINT_INT "):

#include <stdio.h>
#define PTRINT_SHORT
#ifdef PTRINT_SHORT
    typedef short ptrint;
#endif
#ifdef PTRINT_INT
    typedef int ptrint;
#endif
#ifdef PTRINT_LONG
    typedef long ptrint;
#endif
#ifdef PTRINT_LONGLONG
    typedef long long ptrint;
#endif

int main(void) {
    if (sizeof(ptrint) != sizeof(void*)) {
        printf ("ERROR: ptrint doesn't match void* for this platform.\n");
        printf ("   sizeof(void*    ) = %d\n", sizeof(void*));
        printf ("   sizeof(ptrint   ) = %d\n", sizeof(ptrint));
        printf ("   =================\n");
        printf ("   sizeof(void*    ) = %d\n", sizeof(void*));
        printf ("   sizeof(short    ) = %d\n", sizeof(short));
        printf ("   sizeof(int      ) = %d\n", sizeof(int));
        printf ("   sizeof(long     ) = %d\n", sizeof(long));
        printf ("   sizeof(long long) = %d\n", sizeof(long long));
        return 1;
    }

    /* rest of your code here */

    return 0;
}

在我的系统(Ubuntu 8.04,32位)上,我得到:

ERROR: ptrint typedef doesn't match void* for this platform.
   sizeof(void*    ) = 4
   sizeof(ptrint   ) = 2
   =================
   sizeof(short    ) = 2
   sizeof(int      ) = 4
   sizeof(long     ) = 4
   sizeof(long long) = 8

在这种情况下,我知道我需要使用 PTRINT_INT (或 long)进行编译。 可能有一种方法可以在编译时使用 #if 捕获它,但我现在懒得去研究它。 如果您遇到的平台没有足够的整数类型来保存指针,那么您就不走运了。

请记住,使用特殊指针值 (1,2,3) 来表示整数也可能不适用于所有平台 - 这实际上可能是指针的有效内存地址。

不过,如果你不理睬我的建议,我也无能为力阻止你。 毕竟这是你的代码:-)。 一种可能是检查 malloc 的所有返回值,如果得到 1、2 或 3,则再次 malloc(即,有一个 mymalloc() 会自动执行此操作)。 这将是一个轻微的内存泄漏,但它会保证特殊指针和真实指针之间不会发生冲突。

Simply put, no. Not guaranteed on all architectures.

My question is: why? If you want to allocate a type big enough to store a void*, the best thing to allocate is (surprisingly enough :-) a void*. Why is there a need to fit it within an int?

EDIT: Based on your comments to your duplicate question, you want to store special values of the pointer (1,2,3) to indicate extra information.

NO!! Don't do this!!. There is no guarantee that 1, 2 and 3 aren't perfectly valid pointers. That may be the case in systems where you're required to align pointers on 4-byte boundaries but, since you asked about all architectures, I'm assuming you have portability as a high value.

Find another way to do it that's correct. For example, use the union (syntax from memory, may be wrong):

typedef struct {
    int isPointer;
    union {
        int intVal;
        void *ptrVal;
    }
} myType;

Then you can use the isPointer 'boolean' to decide if you should treat the union as an integer or pointer.

EDIT:

If execution speed is of prime importance, then the typedef solution is the way to go. Basically, you'll have to define the integer you want for each platform you want to run on. You can do this with conditional compilation. I would also add in a runtime check to ensure you've compiled for each platform correctly thus (I'm defining it in the source but you would pass that as a compiler flag, like "cc -DPTRINT_INT"):

#include <stdio.h>
#define PTRINT_SHORT
#ifdef PTRINT_SHORT
    typedef short ptrint;
#endif
#ifdef PTRINT_INT
    typedef int ptrint;
#endif
#ifdef PTRINT_LONG
    typedef long ptrint;
#endif
#ifdef PTRINT_LONGLONG
    typedef long long ptrint;
#endif

int main(void) {
    if (sizeof(ptrint) != sizeof(void*)) {
        printf ("ERROR: ptrint doesn't match void* for this platform.\n");
        printf ("   sizeof(void*    ) = %d\n", sizeof(void*));
        printf ("   sizeof(ptrint   ) = %d\n", sizeof(ptrint));
        printf ("   =================\n");
        printf ("   sizeof(void*    ) = %d\n", sizeof(void*));
        printf ("   sizeof(short    ) = %d\n", sizeof(short));
        printf ("   sizeof(int      ) = %d\n", sizeof(int));
        printf ("   sizeof(long     ) = %d\n", sizeof(long));
        printf ("   sizeof(long long) = %d\n", sizeof(long long));
        return 1;
    }

    /* rest of your code here */

    return 0;
}

On my system (Ubuntu 8.04, 32-bit), I get:

ERROR: ptrint typedef doesn't match void* for this platform.
   sizeof(void*    ) = 4
   sizeof(ptrint   ) = 2
   =================
   sizeof(short    ) = 2
   sizeof(int      ) = 4
   sizeof(long     ) = 4
   sizeof(long long) = 8

In that case, I'd know I needed to compile with PTRINT_INT (or long). There may be a way of catching this at compile time with #if, but I couldn't be bothered researching it at the moment. If you strike a platform where there's no integer type sufficient for holding a pointer, you're out of luck.

Keep in mind that using special pointer values (1,2,3) to represent integers may also not work on all platforms - this may actually be valid memory addresses for pointers.

Still ,if you're going to ignore my advice, there's not much I can do to stop you. It's your code after all :-). One possibility is to check all your return values from malloc and, if you get 1, 2 or 3, just malloc again (i.e., have a mymalloc() which does this automatically). This'll be a minor memory leak but it'll guarantee no clashes between your special pointers and real pointers.

我家小可爱 2024-07-20 10:37:32

C99 标准定义了标准 int 类型:

7.18.1.4 能够保存对象指针的整数类型
以下类型指定一个有符号整数类型,其属性是任何有效的 void 指针都可以转换为该类型,然后转换回 void 指针,结果将与原始指针进行比较:

<前><代码> intptr_t

以下类型指定无符号整数类型,其属性是任何有效的 void 指针都可以转换为该类型,然后转换回 void 指针,结果将与原始指针进行比较:

<前><代码> uintptr_t

这些类型是可选的。

C99还定义了size_t和ptrdiff_t:

类型是

<前><代码> ptrdiff_t

这是两个指针相减结果的有符号整数类型;

<前><代码> size_t

这是sizeof运算符结果的无符号整数类型; 和

体系结构的对象最大大小等于整个内存,因此 sizeof(size_t) == sizeof(void*),但我不知道有什么可以移植到 C89 (其中 < code>size_t 是)并保证足够大(其中 uintptr_t 是)。

The C99 standard defines standard int types:

7.18.1.4 Integer types capable of holding object pointers
The following type designates a signed integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:

    intptr_t

The following type designates an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:

   uintptr_t

These types are optional.

C99 also defines size_t and ptrdiff_t:

The types are

  ptrdiff_t

which is the signed integer type of the result of subtracting two pointers;

  size_t

which is the unsigned integer type of the result of the sizeof operator; and

The architectures I've seen have the maximum size of an object equal to the whole memory, so sizeof(size_t) == sizeof(void*), but I'm not aware of anything that is both portable to C89 ( which size_t is ) and guaranteed to be large enough ( which uintptr_t is ).

谁的年少不轻狂 2024-07-20 10:37:32

这在标准 32 位系统上是正确的,但当然不能保证,并且您可能会发现许多体系结构并非如此。 例如,一个常见的误解是 x86_64 上的 sizeof(int) 将为 8(我猜是因为它是 64 位系统),但事实并非如此。 在 x86_64 上,sizeof(int) 仍然是 4,但 sizeof(void*) 是 8。

This would be true on a standard 32 bit system, but there certainly are no guarantees, and you could find lots of architectures where it isn't true. For example, a common misconception is that sizeof(int) on x86_64 would be 8 (since it's a 64 bit system, I guess), which it isn't. On x86_64, sizeof(int) is still 4, but sizeof(void*) is 8.

尴尬癌患者 2024-07-20 10:37:32

这个问题的标准解决方案是编写一个小程序来检查所有 int 类型(short int、int、long int)的大小并将它们与 void* 进行比较。 如果存在匹配,它会发出一段定义 intptr 类型的代码。 您可以将其放入头文件中并使用新类型。

将此代码包含在构建过​​程中很简单(例如,使用 make

The standard solution to this problem is to write a small program which checks the sizes of all int types (short int, int, long int) and compares them to void*. If there is a match, it emits a piece of code which defines the intptr type. You can put this in a header file and use the new type.

It's simple to include this code in the build process (using make, for example)

阳光的暖冬 2024-07-20 10:37:32

不,最接近可移植指针的整数类型是 intptr_tptrdiff_t

No, the closest you will come to a portable pointer-capable integer type would be intptr_t and ptrdiff_t.

牛↙奶布丁 2024-07-20 10:37:32

不,

我不相信 C 标准甚至指定了标准 int 大小。 将其与所有架构(8/16/32/64 位等)结合起来,没有办法保证任何事情。

No.

I do not believe the C standard even specifies standard int sizes. Combine that with all the architectures out there (8/16/32/64bit etc) and there is no way to guarantee anything.

在巴黎塔顶看东京樱花 2024-07-20 10:37:32

int 数据类型将是大多数架构上的答案。

但对于任何(微)架构,都没有没有保证。

int data type would be the answer on most architectures.

But thre is NO guarantee to this for ANY (micro)architecture.

谁人与我共长歌 2024-07-20 10:37:32

答案似乎是“否”,但如果您需要的只是一种可以同时充当两者的类型,则可以使用联合:

union int_ptr_t {
    int i;
    void* p;
};

The answer seems to be "no", but if all you need is a type that can act as both, you can use a union:

union int_ptr_t {
    int i;
    void* p;
};
月依秋水 2024-07-20 10:37:32

通常 sizeof(*void) 取决于内存总线宽度(尽管不一定 - RISC AS/400 之前有 48 位地址总线,但有 64 位指针),并且 int 通常与 CPU 的通用寄存器一样大(有也有例外 - SGI C 在 64 位 MIPS 上使用 32 位整数)。

所以没有任何保证。

Usually sizeof(*void) depends on memory bus width (although not necessarily - pre-RISC AS/400 had 48-bit address bus but 64-bit pointers), and int usually is as big as CPU's general-purpose register (there are also exceptions - SGI C used 32-bit ints on 64-bit MIPS).

So there is no guarantee.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文