sizeof运算符的实现

28

我尝试实现sizeof运算符。 我已经这样做了:

#define my_sizeof(x) ((&x + 1) - &x)

然而,最终结果总是为任一数据类型提供'1'。

然后我通过Google搜索找到了以下代码:

#define my_size(x) ((char *)(&x + 1) - (char *)&x)

当进行类型转换后,代码能够正常工作,但我不明白为什么。该代码也完美地填充了一个结构体。

它也适用于:

#define my_sizeof(x) (unsigned int)(&x + 1) - (unsigned int)(&x)

有人能解释一下如果进行了类型转换,它是如何工作的吗?


4
将变量转换为unsigned int是个不好的主意。uintptr_t更好一些,但仍涉及烦人却无法避免的隐式转换。 - Pascal Cuoq
你基本上不能实现sizeof。它是C语言的重要组成部分。 - Basile Starynkevitch
10个回答

31

指针相减的结果是以 元素 而不是字节为单位。因此,根据定义,第一个表达式的值为 1

除此之外,在宏中你确实应该使用括号:

#define my_sizeof(x) ((&x + 1) - &x)
#define my_sizeof(x) ((char *)(&x + 1) - (char *)&x)
否则,在表达式中尝试使用my_sizeof()可能会导致错误。

Otherwise attempting to use my_sizeof() in an expression can lead to errors.

返回:

否则,在表达式中尝试使用my_sizeof()可能会导致错误。


15
宏无法取代sizeof运算符,因为它们会对参数进行评估(而且还会评估两次)……试想一下my_sizeof(x++) - Mat

9
#define my_sizeof(x) ((char *)(&x + 1) - (char *)&x)

这个my_sizeof()宏在以下情况下无法工作:

  1. sizeof 1 - 4字节(对于一个4字节的int平台)
    my_sizeof(1) - 根本无法编译。

  2. sizeof (int) - 4字节(对于一个4字节的int平台)
    my_sizeof(int) - 根本无法编译代码。

它只适用于变量,而不适用于数据类型,如intfloatchar等,也不适用于字面量,如23.4'A'等,也不适用于rvalue表达式,如a+bfoo()


2
这将是一个很好的评论,因为它没有回答所问的问题,但它是“指导作者改进帖子的建设性批评”。 - autistic
它也无法正确报告大小,因为存在对齐问题。例如,一个6字节大小的变量将报告8。 - Ol Sen
如果 &x+1&x 多8个字节,那么 事实上 sizeof(x) 是8: "对于指针减法,字符指针之间的差别结果类似地被原始指向的对象大小除。" - Andrew Henle

8
sizeof 运算符是 C (和 C++) 语言规范的一部分,由编译器(前端)实现。除非使用 GCC 扩展(如 typeof),否则无法使用其他 C 结构来实现它,因为它可以接受类型或表达式作为操作数,而不会产生任何副作用(例如,sizeof((i>1)?i:(1/i))i==0 时不会崩溃,但您的宏 my_sizeof 将因除以零而崩溃)。另请参见 C 编码准则wikipedia
您应该了解 C pointer arithmetic。例如,请参见 this question。指针差异以元素而不是字节表示。

8
#define my_sizeof(x) ((&x + 1) - &x)
&x表示程序中声明的变量(假设为双精度型变量x)的地址;将其加1后得到下一个与x相同类型的变量地址(此处为 addr_of(x) + 8,因为双精度型变量占用8个字节)。
通过求差可以得出在这段内存中能够存储多少个与x类型相同的变量,对于类型x来说显然是1(因为我们只是将其加了1并求差)。
#define my_size(x) ((char *)(&x + 1) - (char *)&x)

将其转换为char*类型并计算差值,可以告诉我们在给定的内存空间中可以存储多少个char类型变量(差异)。由于每个char仅需要1字节的内存,因此(内存数量)/1将给出传递到宏的变量类型的连续两个内存位置之间的字节数,从而得出变量x所需的内存量。

但是你无法通过这个宏来传递任何文字并知道它们的大小。


6

但最终结果总是返回'1',无论哪种数据类型

是的,这就是指针算术运算的工作原理。它按照指向的类型单位进行计算。因此将其转换为char *会按照char的单位进行计算,这正是您想要的。


2

这将适用于文字和变量。

#define my_sizeof(x) (char*) (&(((__typeof__(x) *)0)[1])) - (char *)(&(((__typeof__(x) *)0)[0]))

1
#define my_sizeof(x) ((&x + 1) - &x)
  • 这基本上是(两个内存值的差)/(数据类型的大小)。

  • 它告诉你可以存储多少个x类型元素。这是1。你可以在这个内存空间中放一个完整的x元素。

  • 当我们将其强制转换为其他数据类型时,它表示可以在此内存空间中存储多少个该数据类型的元素。

#define my_size(x) ((char *)(&x + 1) - (char *)&x)
  • 将其强制类型转换为(char *)可以让你获得准确的内存字节数,因为char占用一个字节。
#define my_sizeof(x) (unsigned int)(&x + 1) - (unsigned int)(&x)
  • 如果你将指针类型转换为int,它会给你编译错误。

欢迎来到 Stack Overflow。请阅读 https://stackoverflow.com/editing-help 了解如何使用 Markdown 格式化答案。 - Chris

0

我昨天搜索了一下,找到了这个宏:

#define mysizeof(X)  ((X*)0+1)

它只扩展X一次(不会出现像x++这样的表达式的双重评估错误),并且到目前为止它运行良好。


尽管这个宏在我用结构体进行测试时没有错误,但使用 <sizeof()> 操作符覆盖了更广泛的情况。例如,我的 mysizeof(2) 无法编译,但 sizeof(2) 可以得到整数的大小为4。 - C.Y
预期表达式。 - Ol Sen

-1

# 定义 my_sizeof(x) ((&x + 1) - &x)

&x 给出了变量的地址,将其增加一 (&x + 1),将给出另一个类型为 x 的变量可以存储的地址。 现在,如果我们对这些地址进行算术运算,如 ((&x + 1) - &x),那么它将告诉我们在 ((&x + 1) - &x) 地址范围内可以存储 1 个类型为 x 的变量。

现在,如果我们将该内存量强制转换为 (char *) [因为 char 的大小为 1 字节,增加 char * 将仅移动一个字节],那么我们将得到类型 x 占用的字节数


-1
#include<bits/stdc++.h>

using namespace std;
//#define mySizeOf(T) (char*)(&T + 1) - (char*)(&T)

        template<class T>
size_t mySizeOf(T)
{
        T temp1;
        return (char*)(&temp1 + 1) - (char*)(&temp1);
}
int main()
{
        int num = 5;
        long numl = 10;
        long long numll = 100;
        unsigned int num_un_sz = 500;

        cout<<"size of int="<<mySizeOf(num) << endl;
        cout<<"size of long="<<mySizeOf(numl) << endl;
        cout<<"size of long long ="<<mySizeOf(numll) << endl;
        cout<<"size of unsigned int="<<mySizeOf(num_un_sz) << endl;
        return 0;
}

1
<bits/stdc++.h> 不是标准头文件。 - Basile Starynkevitch

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