Подтвердить что ты не робот

Правильно ли C обрабатывает sizeof (...) и sizeof... в этом случае?

В следующем коде представлены функции test и test2 эквивалентные?

typedef int rofl;

void test(void) {
    rofl * rofl = malloc(sizeof(rofl)); // Is the final rofl here the TYPE?
}

void test2(void) {
    rofl * rofl = malloc(sizeof *rofl); // Is the final rofl here the VARIABLE?
}

Другими словами:

  • Правильно ли rofl в sizeof(rofl) выбрать тип rofl из-за круглых скобок?
  • Правильно ли rofl в sizeof *rofl выбрать переменную rofl из-за недостатка круглых скобок?

Примечание.. Это глупый пример, но на практике может быть фактически, что у вас есть имя типа, такое же, как имя переменной. Отсюда вопрос.

4b9b3361

Ответ 1

В обоих случаях последним rofl является имя переменной. Имя переменной находится в области видимости сразу после ее появления; и для остальной части текущего объема этот идентификатор в обычном контексте (*) всегда означает имя переменной.

Оператор sizeof не вводит никаких особых случаев для поиска имени. На самом деле не существует языковых конструкций, которые будут использовать скрытый смысл идентификатора.

На практике неплохо не использовать один и тот же идентификатор для типа и имени переменной.


(*) Существует три специальных контекста для идентификаторов: имена ярлыков, теги структуры и элементы структуры. Но во всех других контекстах все идентификаторы имеют общее пространство имен: для имен типов не существует отдельных пространств имен идентификаторов и имен переменных по сравнению с именами функций и т.д.

Вот надуманный пример:

typedef int A;      // "A" declared as ordinary identifier, meaning a type name

struct A { A A; };  // "A" declared as struct tag and member name -- OK as these are three different name spaces. Member type is "int"

A main()            // int main() - ordinary context
{
    struct A A();   // "A" declared as ordinary identifier, meaning a function name; hides line 1 A
    // A C;         // Would be error: ordinary A is a function now, not a typedef for int
    struct A B;     // OK, struct tags have separate name space
    A:+A().A;       // OK, labels and struct members have separate name space, calls function
    goto A;         // OK, label name space
}

Ответ 2

В этом объявлении

rofl * rofl = malloc(sizeof(rofl)); // Is the final rofl here the TYPE?

имя переменной rofl скрывает имя typedef rofl. Таким образом, в операторе sizeof используется указатель rofl, то есть выражение имеет тип int *.

То же самое верно для этого объявления

rofl * rofl = malloc(sizeof *rofl); 

за исключением того, что используется выражение с разыменованным указателем rofl, который имеет тип typedef name rofl, который является типом int.

Кажется, что путаница возникает из-за этого определения грамматики C

sizeof unary-expression
sizeof ( type-name )

Однако unary-expression может быть основным выражением, которое является выражением, заключенным в круглые скобки.

Из стандарта C (6.5.1 Первичные выражения)

primary-expression:
    ( expression )
    //...

Так, например, если x - это имя переменной, вы можете написать либо

sizeof x 

или

sizeof( x )

Для ясности вы можете вставить пробелы между оператором sizeof и основным выражением

sizeof    ( x )
operator  primary expression

Для сравнения рассмотрим еще один унарный оператор: унарный плюс. Вы можете написать, например,

+ x

или

+ ( x )

Теперь просто замените унарный плюс на другой унарный оператор sizeof.

Что касается скрытия имен, то проблема разрешима для структур, объединений и перечислений, потому что их имена включают ключевые слова для тегов.

Например

typedef struct rofl { int x; } rofl;

void test(void) {
    rofl * rofl = malloc(sizeof( struct rofl));
}

В этой функции с оператором sizeof используется имя типа struct rofl.

В этой функции

typedef struct rofl { int x; } rofl;

void test(void) {
    rofl * rofl = malloc(sizeof( rofl));
}

с помощью оператора sizeof используется первичное выражение с переменной rofl, которая имеет тип struct rofl *.

Ответ 3

Нет выбора "выбора" или "выбора". В обоих случаях rofl, упомянутый в каждом вызове sizeof, является переменной, а не типом, из-за правил определения области. Переменная объявляется во внутренней области и, таким образом, переопределяет имя типа. Скобка для аргумента оператору sizeof не имеет значения.

Желаем удачи.