2015-01-28 2 views
2

Стандарта c11 говорят, что SizeOf,SizeOf применяется для типов массивов

«применительно к операнду, который имеет тип массива, то результат будет общего числа байт в массиве»

  • (6.5.3.4, bullet 4).

Нога примечание (103) говорит:

«При применении к параметру, объявленному иметь массив или функцию типа, оператор SizeOf дает размер скорректированному (указатель) типа».

Я беру из этого, что при применении к типу массива sizeof дает размер массива (количество элементов x по размеру элементов), но применяется к параметрам, объявленным для типа массива, и дает размер указатель.

Мой вопрос:

Как можно иметь объект типа массива, который не производит размер указателя, в связи с сноске?

Я чувствую, что в некоторых обстоятельствах я не могу доверять оператору sizeof, не зная об этом.

Спасибо.

EDIT: Я предполагаю, что я должен уточнить свою озабоченность, если определена «int a [4]», тогда я вижу ответы от размера sizeof == 4 * sizeof (int), но как насчет sizeof (a + 0)? Кажется, что sizeof (a + 1) должен быть оценен как указатель. Меня беспокоят обстоятельства, отличные от вызовов функций, где массив распадается на указатель.

+0

По сути, вы просто должны знать, что массивы распадаются на указатели при передаче в качестве параметров, поэтому не используйте 'sizeof' для массива, который передается вам в качестве параметра. –

+0

Он просто повторяет, что 'void f (char p [])' объявляет параметр 'p' для указания типа указателя. – immibis

ответ

2

В ответ на ваше обновление (беспокоясь о sizeof(foo+1) типа ситуаций:

Да, sizeof применяется к array_name + int эквивалентно sizeof &(array_name[int]);, на том основании, что массив, затухает в указатель в тех случаях, Точно так же, к. добраться до фактического значения из массива вы не пишете arr_name + 1, а *(arr_name + 1).

Таким образом, принимая во внимание сноску, когда будет sizeof выход фактический размер массива (в байтах)?Для этого, обратите внимание на то, что говорит стандарт о массивах распадающихся на указатели:

исключением случаев, когда это операнд оператора SizeOf или одноместный & оператора, или строковый литерал используется для инициализации массива, выражение который имеет тип '' array of type '', преобразуется в выражение с указателем типа '' to type '', который указывает на начальный элемент объекта массива и не является lvalue.

Значение:

  • Использование sizeof непосредственно на переменном массиве (sizeof array_var)
  • Разыменование указателя на массив (sizeof *(&array_var)) Примечания: Это относится также, когда вы передаете этот указатель на массив к другой функции, но не всегда лучший способ пойти (см. пример ниже)
  • строковые литералы (например, Rvalue в char foo[] = "foobar"; =>sizeof("foobar");)

Во всех других случаях (AFAIK), массив распадается на указатель, и sizeof даст размер указателя:

  • Арифметика на массиве => арифметика указателей (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 вызовет ошибку («недопустимое применение„SizeOf“неполного типа" обугливается []»). Поскольку этот способ передачи массива вокруг весьма подвержен ошибкам (правильный размер должен быть определен везде), это намного чаще распространены, чтобы просто позволить распад массива, и передать второй аргумент вместе с ним:

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

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 *).

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); 
} 
+0

'sizeof (a)' is 'sizeof (int *)' не потому, что аргумент распадается при вызове, а потому, что 'int a []' * скорректирован * на 'int * a'. Распад массива означает, что вы можете вызывать 'func (array)' даже если 'array' является массивом. – juanchopanza

+0

Внутри функции это * * указатель, потому что параметр функции отрегулирован на указатель. Таким образом, распад происходит, когда вы передаете массив функции. Я добавил несколько объяснений в свой ответ. – juanchopanza

+0

@juanchopanza Да, я понимаю, что вы говорите. благодаря – Gopi

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 массив междунар». Оператор sizeof имеет доступ к этой информации (времени компиляции) и, следовательно, может дать правильный размер для этого типа.

Обратите внимание, что это связано с распадом массива, где в некоторых случаях массив может «распадаться» на указатель на его первый элемент. Это распад, что позволит вам вызвать foo с аргументом массива:

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

int* p = a; // same phenomenon 

Так, регулировка изменяет функцию подписи и распад позволяет передать массив в функцию, которая ожидает указатель.

Update Что касается вашего обновления, применение бинарных арифметических операторов один из многих случаев, когда массив распадается на указатель на его первый элемент. Например

#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

Сноска относится к параметру (функции).

например.

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

param_arr является параметром функции - и в то время как он выглядит как массив, это действительно указатель (int *). Таким образом, размер param_arr дает размер int *.

local_arr не является параметром. Таким образом sizeof дает размер этого массива.

0

Как распад массивов в указатели, когда массив передается функционировать в качестве параметра мы можем проиллюстрировать это, как объявить параметр как массив, как показано ниже,

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

Теперь выше декларация интерпретируется компилятором по-разному как декларация указателя, так как функция фактически получает указатель на arrya типа T, как показано ниже:

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

Следовательно, компилятор делает вид, что параметр массива, объявленный как указатель (типа char *) и sizeof, даст размер указателя фактически вместо размера массива.

Пример:

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

Выход acutually 4 и не 10.