Вопрос: Правильно ли 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?
}

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

  1. Есть ли rofl в sizeof(rofl) правильно выбрать rofl  тип  из-за круглых скобок?
  2. Есть ли rofl в sizeof *rofl правильно выбрать rofl  переменная  из-за отсутствие  круглых скобок?

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


38


источник


Ответы:


В обоих случаях последний 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's 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
}

27



В этой декларации

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 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 *,


13



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

Удачи.


2