sizeof应用于数组类型

时间:2015-01-28 08:33:16

标签: c arrays sizeof c11

c11标准说明了sizeof,

  

“当应用于具有数组类型的操作数时,结果为   数组中的总字节数“

  • (6.5.3.4,bullet 4)。

脚注(103)说:

  

“当应用于声明具有数组或函数类型的参数时,   sizeof运算符产生调整后的(指针)类型的大小“。

我从中可以看出,当应用于数组类型时,sizeof给出了数组的大小(元素数量x元素的大小),但是应用于声明为具有数组类型的参数,它给出了指针的大小。

我的问题:

由于脚注,如何使数组类型的对象不会产生指针的大小?

我觉得在某些情况下我不能相信sizeof运算符而不知道这一点。

感谢。

编辑:我想我应该澄清我的担忧,如果定义了“int a [4]”,那么我从响应中看到a == 4 * sizeof(int)的sizeof,但是sizeof(a + 0) )?看来sizeof(a + 1)必须被评估为指针。我担心除了函数调用之外的情况,其中数组衰减为指针。

6 个答案:

答案 0 :(得分:4)

引用的关键点是" 参数声明具有数组类型"和" 调整后的(指针)类型"。这指的是"数组类型"的函数参数。被调整为指针类型。完成调整后,类型为指针,其大小必须是指针的大小。它不可能是其他任何东西。这是它的工作原理:

void foo(int p[42]);

调整

void foo(int* p);

这两个函数声明是等效的。因此p的类型为int*。并且sizeof(int*)始终是指针的大小。

但是,在不同的上下文中,没有类型调整:

int a[42]; // no adjustment. a is an array of size 42;

sizeof(a); // gives the size of type int[42]

这里,a的类型确实是"大小为42的int"数组。 sizeof运算符可以访问此(编译时)信息,因此可以为该类型提供正确的大小。

请注意,这与数组衰减有关,其中数组可能会衰减"在某些情况下转换为指向其第一个元素的指针。这种衰减可以让你用数组参数调用foo

int a[26];
foo(a);     // foo(int*): a decays to int*

int* p = a; // same phenomenon

因此,调整会更改函数签名, decay 允许您将数组传递给需要指针的函数。

更新 关于您的更新,二进制算术运算符的应用是数组衰减到指向其第一个元素的指针的众多情况之一。例如

#include <stdio.h>

int main(void)
{
    int a[42];
    printf("sizeof(a) = %zu\n", sizeof(a));
    printf("sizeof(a+1) = %zu\n", sizeof(a+1));
    return 0;
}

输出:

sizeof(a) = 168
sizeof(a+1) = 8

答案 1 :(得分:3)

响应您的更新(关注sizeof(foo+1)类型情况:

是的,sizeof应用于array_name + int相当于sizeof &(array_name[int]);,因为数组会在这些情况下衰减为指针。同样,要从数组中获取实际值,您不要写arr_name + 1,而是*(arr_name + 1)

因此,考虑到脚注,sizeof何时会产生实际的数组大小(以字节为单位)?为此,请查看标准对于衰减为指针的数组所说的内容:

  

除非它是sizeof运算符或一元&amp;的操作数。运算符,或者是用于初始化数组的字符串文字,具有类型''数组类型''的表达式将转换为类型为''指向类型'的指针的表达式,指向数组对象的初始元素,不是左值。

含义:

  • 直接在数组变量(sizeof
  • 上使用sizeof array_var
  • 取消引用指向数组的指针(sizeof *(&array_var)注意:这也适用于将此指针传递给另一个函数的数组,但并不总是最好的方法(参见以下示例)
  • 字符串文字(例如char foo[] = "foobar"; =&gt; sizeof("foobar");中的Rvalue)

在所有其他情况下(AFAIK),数组衰减为指针,sizeof将产生指针的大小:

  • array =&gt;上的算术指针算术(sizeof (array_var +1 )
  • 将数组传递给函数(衰减成指针)
  • ...

将数组传递给函数

因此,使用一元&运算符, 可以将指向数组的指针传递给函数,但很少这样做。不过,这是一个例子:

void pointer_to_array(char (*ptr)[]);//pointer to array type
void error_p_to_arr(char (*ptr)[]);

int main ( void )
{
    char str[] = "some random string";//array of 18 bytes
    printf(
        "Sizeof array %zu\n",
        sizeof str
    );
    pointer_to_array(&str);
    return 0;
}
//we need to specify the exact type, including size!
//replace 18 with 10, you're fine, but use 20 and you're in trouble
void pointer_to_array(char (*ptr)[18])
{
    printf(
        "sizeof argument: %zu\nsizeof array %zu",
        sizeof ptr,//4 or 8
        sizeof *ptr//18!! YaY
    );
}
//if we don't specify the array size here
void error_p_to_arr(char (*ptr)[])
{
    printf(
        "sizeof argument: %zu\nsizeof array %zu",
        sizeof ptr,//4 or 8
        sizeof *ptr//ERROR!
    );
}

后者sizeof *ptr会导致错误(&#34;'sizeof'无效应用于不完整类型'char []'&#34; )。因为这种传递数组的方式非常容易出错(必须在任何地方定义正确的大小),所以简单地让数组衰减并传递第二个参数会更常见:

void common_usage(const char *ptr, size_t arr_len);
int main ( void )
{
    char str[] = "some random string";
    common_usage(str, sizeof str/sizeof *str);
    return 0;
}

它看起来更清洁,它更常见,而且更容易维护。

参见示例here

答案 2 :(得分:1)

脚注适用于(函数)参数。

e.g。

void foo(int param_arr[32])
{
     int local_arr[32];
}

param_arr是函数的一个参数 - 虽然它看起来像一个数组,但它确实是一个指针(int *)。因此,param_arr的sizeof会产生int *的大小。

local_arr不是参数。因此sizeof产生该数组的大小。

答案 3 :(得分:0)

拥有一个不会产生指针大小的数组类型的对象很简单:不要在函数参数上执行:

const int foo[32];

printf("hey, foo is %zu bytes\n", sizeof foo);

不会打印sizeof (int *)

这是正常用法,您引用的文本指出,当数组传递给函数时,它会衰减到指针,即使函数的原型指定了数组大小。

所以这个:

static void printsize(int x[100])
{
  printf("the argument is %zu bytes\n", sizeof x);
}

int main(void)
{
  const int foo[100];
  printsize(foo);
  return 0;
}

打印sizeof (int *)

答案 4 :(得分:0)

为了澄清您的疑问,下面的代码可能有所帮助:

void func(int a[])
{
  sizeof(a) is not equal to sizeof(int) * 10 but equal to sizeof(pointer)
  Because int a[] is adjusted to int * 
}

int main()
{
int a[10];
int *p = a;
//Initialize
//sizeof(a) = sizeof(int) * 10 

//sizeof(p) = sizeof(pointer)

func(a);
}

答案 5 :(得分:0)

当数组衰减为指针时,当一个数组作为参数传递给函数时,我们可以将它说明为将数组声明为数组,如下所示,

void function (char a[])
{ ... }

现在上面的声明被编译器不同地解释为指针声明,因为函数实际上接收到类型为T的arrya的指针,如下所示:

void function(char *a)
{ ... }

因此,编译器假装声明为指针(类型为char *)和sizeof的数组参数实际上会给出指针的大小而不是数组的大小。

示例:

void function (char a[10])
{
    int i = sizeof(a);
    printf("%d\n", i);
}

输出是4而不是10