Кто-то тоже использует имя структуры в качестве имени переменной. Что на самом деле говорит код? - PullRequest
11 голосов
/ 20 апреля 2010

Этим утром мы нашли старый кусок кода, который вызывал сбой вызова библиотеки.

struct   fred
{
    int     a;
    int     b;
    int     c;
};

fred     fred[MAX_SIZE+1];

memset( fred, 0, sizeof(fred) * MAX_SIZE+1 );

Похоже, что sizeof (fred), возможно, был полным размером массива, а не размером структуры, так как он перезаписывал большое памяти.

Тот факт, что он был скомпилирован без предупреждения на нескольких разных системах, показался странным.

Существует ли правильная семантика для этого случая, когда тип и имя переменной сталкиваются? или это какое-то неопределенное поведение? или просто дефект?

Ответы [ 5 ]

14 голосов
/ 20 апреля 2010

Во-первых, не делайте этого, потому что это сбивает с толку - но вы уже обнаружили это.

Переменная скрывает имя структуры, но вы все равно можете использовать struct fred для ссылки на тип.

, например

fred     fred[MAX_SIZE+1];

memset( fred, 0, sizeof(struct fred) * (MAX_SIZE+1) );

Кроме того, почему бы просто не использовать размер всего объекта. Таким образом, ваш memset вызов является надежным перед лицом изменений размера или типа массива. Вы можете сделать:

memset( fred, 0, sizeof fred );

Вы должны иметь круглые скобки при использовании идентификатора типа с sizeof, но это не требуется при использовании объекта.

2 голосов
/ 10 января 2013

Последнее объявление имеет приоритет:

[C++03: 9.1/2]: Определение класса вводит имя класса в область, в которой оно определено, и скрывает любой класс, объект, функцию или другое объявление этого имени в прилагаемой области (3.3). Если имя класса объявлено в области видимости, где объект, функция или перечислитель с тем же именем также объявлены, тогда, когда оба объявления находятся в области видимости, к классу можно обращаться только с использованием подробного спецификатор типа (3.4.4).

подробный спецификатор типа - это когда вы вставляете struct или class в начале типа; это фактически устраняет неоднозначность, хотя, строго говоря, и из-за приведенного выше правила поиск, во-первых, никогда не был действительно двусмысленным.

Итак:

void foo()
{
   struct bar {};
   bar bar[5];

   memset(bar, 0, sizeof(bar));
   //             ^^^^^^^^^^^
   //                  5

   memset(bar, 0, sizeof(struct bar));
   //             ^^^^^^^^^^^^^^^^^^
   //                  1
}

// (NB. Exact sizes may differ; 1 and 5 given as relative examples only)

Тот факт, что все это четко определено, является одной из причин, по которой вы не получили предупреждение. Тем не менее, я бы надеялся , что интеллектуальный компилятор определит ваш код как возможную ошибку программиста & mdash; рационализация того, почему какая-то конкретная реализация выдает или не выдает какое-то данное предупреждение в некомандатном случае, однако, в значительной степени глупо.

2 голосов
/ 20 апреля 2010

Разве это не должно быть sizeof (fred) * (MAX_SIZE + 1), поскольку ваш массив имеет длину MAX_SIZE + 1?

1 голос
/ 20 апреля 2010

Когда вы определяете переменную, она скрывает имя типа, поэтому да, когда вы делаете sizeof(fred), вы получаете размер массива, а не размер структуры. это довольно легко проверить, просто распечатав sizeof(fred).

Короткий ответ, однако, просто: «не делай этого».

0 голосов
/ 20 апреля 2010

За исключением случаев размера во время выполнения, типичным идиоматическим способом использования memset (а также memcpy, malloc и т. Д.) Является выполнение

memset(dst_ptr, 0, sizeof *dst_ptr);

или, что эквивалентно,

memset(&dst_object, 0, sizeof dst_object);

Как это должно было быть использовано и в этом случае

memset(&fred, 0, sizeof fred);

и проблема с конфликтом имен не возникнет. Вариант memset(fred, 0, sizeof fred) также будет работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...