Nano Hash - криптовалюты, майнинг, программирование

использование ключевого слова struct в объявлении переменной в C++

У меня есть ощущение, что это может быть связано с синтаксисом C, но я начал свою жизнь программирования с C++, поэтому я не уверен.

В основном я видел это:

struct tm t;
memset( &t, 0, sizeof(struct tm) );

Меня немного смущает этот синтаксис, так как обычно я ожидаю, что приведенное выше будет выглядеть так:

tm t;
memset( &t, 0, sizeof(tm) );

В чем разница между ними и почему вместо них используется первый?

Обновлять

Структура tm, о которой я говорю, находится в wchar.h, и ее определение выглядит следующим образом:

struct tm {
        int tm_sec;     /* seconds after the minute - [0,59] */
        int tm_min;     /* minutes after the hour - [0,59] */
        int tm_hour;    /* hours since midnight - [0,23] */
        int tm_mday;    /* day of the month - [1,31] */
        int tm_mon;     /* months since January - [0,11] */
        int tm_year;    /* years since 1900 */
        int tm_wday;    /* days since Sunday - [0,6] */
        int tm_yday;    /* days since January 1 - [0,365] */
        int tm_isdst;   /* daylight savings time flag */
        };
11.10.2011

  • struct tm взят из стандартной библиотеки C и должен быть найден в файле time.h, а не в файле wchar.h. 11.10.2011
  • Вероятно, это так, но он также есть в wchar.h на моей платформе (MSVC). Определение структуры обернуто ifndef защитной проверкой для _TM_DEFINED, но это не имеет отношения к моему первоначальному вопросу. 11.10.2011
  • возможный дубликат определения структуры typedef и структуры 11.10.2011
  • @Praetorian Оглядываясь назад, это всего лишь дубликат. Моя первоначальная путаница исходит из другой точки зрения, которая по-прежнему ценна и является действительной и полезной альтернативой поиску, возможно, той же информации. 11.10.2011

Ответы:


1

Простой ответ заключается в том, что здесь присутствует ключевое слово struct, чтобы ограничить поиск идентификатора tm только определяемыми пользователем типами классов. Вероятно, он оставлен для совместимости с C, где это требуется.

Вопреки тому, что говорят другие, не существует такой вещи, как auto-typedef, и C и C++ не отличаются в отношении того, как управляются идентификаторы для определяемых пользователем типов. Разница только в поиске.

Вы можете прочитать больше здесь

11.10.2011
  • C и C++ различаются в отношении того, как управляются идентификаторы для пользовательских типов, двумя способами. Во-первых, в C имена structs, unions и enums находятся в отдельном пространстве имен, которое используется вместо обычного пространства имен при поиске имен за этими ключевыми словами. Такие имена никогда не могут конфликтовать с другими именами в C, и такие имена никогда не будут найдены, за исключением случаев, когда они следуют за одним из этих ключевых слов. C++ имеет специальные правила для разрешения конфликтов и их разрешения, но только в случае возникновения конфликта. 11.10.2011
  • И, в отличие от C++, в C, даже если struct определен в другом struct, его имя такое же, как если бы оно было определено вне инкапсулирующего struct. Таким образом, в C++ struct A { struct B {}; }; определяет две структуры: A и A::B. В C++ он также определяет две структуры: struct A и struct B. 11.10.2011
  • @JamesKanze: концептуально C ++ по-прежнему поддерживает два пространства имен с той разницей, что определяемые пользователем типы будут искаться в случае сбоя поиска в общем пространстве имен. Как и в C, имена определяемых пользователем типов не могут конфликтовать с другими идентификаторами (переменными, функциями) — определение типа приведет к добавлению идентификатора в общее пространство имен, что может вызвать проблемы. Опять же, как я уже говорил, разница не в поиске. Другое отличие (вложенные структуры) верно и связано с отсутствием искажения идентификаторов в языке Си. 12.10.2011
  • Стандарт С++ описывает это не так. В §3.3.10/2 говорится о том, что имя класса или имя перечисления скрывается, когда что-то еще объявляется в той же области, а в §3.3.1/4 говорится об объявлении имени класса или имени перечисления в той же области, что и другие имена. . 12.10.2011
  • В §3.4/1 также говорится, что правила поиска имен применяются одинаково ко всем именам (включая имена typedef (7.1.3), имена пространств имен (7.3) и имена классов (9.1)) везде, где грамматика допускает такие имена в контексте обсуждаются по определенному правилу. Правило, насколько я понимаю, состоит в том, что другое имя будет скрывать имя класса или перечисления, за исключением случаев, когда другое имя не может использоваться по закону (на практике, только в уточненном спецификаторе типа). 12.10.2011
  • @JamesKanze: я думаю, что мы говорим об одном и том же по-разному. Вы смотрите сверху вниз, из описаний в стандарте, а я смотрю снизу вверх: для реализации этих ограничений (в частности, скрытия) компилятор должен (концептуально это можно было бы реализовать с помощью тегов) поддерживать разные наборы идентификаторов в контексты. Я думаю, мы согласны с тем, что не существует auto-typedef и что идентификаторы типов должны обрабатываться иначе, чем другие идентификаторы, верно? 12.10.2011
  • Родригес Эффекты должны быть такими же; там, конечно, нет auto-typedef. Что касается реализации --- я бы, вероятно, обработал их чем-то вроде перегруженных символов, с разрешением перегрузки в зависимости от контекста, в котором использовался символ, вместо того, чтобы поддерживать две разные таблицы поиска (обе с реализацией нетривиального правила сферы). В C проблема несколько проще, потому что нет struct области видимости для структур. (Однако область действия по-прежнему существует.) 12.10.2011

  • 2

    В C имена структурных тегов не формируют идентификаторы в глобальном пространстве имен.

    struct not_a_global_identifier { /* ... */ };
    

    Чтобы обратиться к этой структуре, вы должны использовать ключевое слово struct (чтобы указать пространство имен)

    struct not_a_global_identifer object;
    

    или создайте новый идентификатор в глобальном пространстве имен с typedef

    typedef struct not_a_global_identifer { /* ... */ } global_name_space_identifier;
    

    В C есть 4 пространства имен, см. 6.2.3 в Стандарт C99:

    • названия ярлыков
    • теги структур, союзов и перечислений
    • члены структур или объединений (ни единого пространства имен ... столько, сколько определено структур или объединений)
    • глобальное пространство имен для всех остальных идентификаторов

    Это легальная программа на C :-)

    int main(void) {
      typedef struct foobar { int foobar; } foobar;
      foobar boo;
      boo.foobar = 42;
      if (boo.foobar) goto foobar;
    foobar:
      return 0;
    }
    
    11.10.2011
  • Итак, имея это в виду, в C я могу объявить глобальную структуру с именем struct foo {};, а также рядом с ней глобальную переменную с тем же именем, int foo;, и не будет конфликта? 11.10.2011
  • Да. Вы можете без проблем иметь один и тот же идентификатор в разных пространствах имен. В приведенном выше коде foobar одновременно является типом (глобальное пространство имен), элементом структуры (пространство имен member), тегом структуры (тег пространство имен) и метка (пространство имен label). 11.10.2011
  • @RobertDailey: не только в C, вы также можете сделать это в C++, и тогда вы столкнетесь с проблемой добавления struct (или class) для объявления переменной: struct X {}; int X; struct X x; Удаление ключевого слова struct из определения x перед вызовом ошибка компилятора. 12.10.2011
  • Большое спасибо, теперь очень ясно. Я вдруг обнаружил, что это своего рода двухуровневая идея... Если этого нет в текущем, перейдите в ящик struct и найдите foobar. 23.11.2018

  • 3

    Использование struct tm t; предназначено для совместимости с C, в котором объявление структуры с именем "tm" определяет тип с именем "struct tm", а не тип с именем "tm" (в отличие от C++, в котором объявлены оба имени для типа).

    11.10.2011

    4

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

    Когда вы обращаетесь к tm, компилятор C (как и компилятор C++) будет искать этот идентификатор в пространстве глобальных идентификаторов. Затем компилятор C++ будет искать в пространстве идентификаторов определяемых пользователем типов, если он не нашел этот символ раньше.

    По сути, если вы хотите иметь то же поведение, что и в C++, добавьте эту строку:

    typedef struct tm tm;
    

    Вы можете комбинировать объявление структуры и typedef следующим образом:

    typedef struct tm { int field } tm;
    

    Или используя анонимную структуру:

    typedef struct { int field } tm;
    

    То же самое относится и к enum и union :

    typedef enum { VALUE } myEnum;
    typedef union { int integer; char charArray[4]; } myUnion;
    
    11.10.2011
  • Auto typedef делает то же, что и я, но автоматически. Поскольку C++ больше ориентирован на тип, тип доступен напрямую. C больше ориентирован на значение переменной, поэтому важно знать, что t — это структура tm, а не просто tm. Обратите внимание, что то же самое происходит с перечислениями и объединениями. 11.10.2011
  • В C++ также нет auto typedef. Эффект typedef заключается в объявлении нового идентификатора в пространстве глобальных идентификаторов для ссылки на тип в пространстве идентификаторов определяемых пользователем типов. То есть typedef struct tm tm; создает новый идентификатор tm для ссылки на struct tm. Поведение typedef точно такое же в C и C++. На самом деле разница заключается в поиске, где C++ будет автоматически искать идентификаторы в пространстве идентификаторов определяемых пользователем типов, если идентификатор ранее не был найден. 11.10.2011
  • @DavidRodríguez-dribeas Не могли бы вы добавить больше деталей к вашему последнему заявлению: will automatically lookup identifiers in the user-defined-types identifier space if the identifier was not previously found. Не уверен, что такое пространство идентификаторов определяемых пользователем типов, и какова точная логика поиска, на которую вы ссылаетесь. 11.10.2011
  • @RobertDailey: вы можете прочитать больше здесь 11.10.2011
  • @DavidRodríguez-dribeas Спасибо, Дэвид. Вы должны опубликовать фактический ответ со всей этой информацией! 11.10.2011

  • 5

    В вашем примере tm может быть структурой типа.

    e.g.

    typedef struct tm_t
    {
      int x; 
    }tm;
    

    и тогда вы можете сделать

    tm t; 
    
    11.10.2011

    6

    Вы можете увидеть ссылку ниже и цитировать оттуда: «В C вы должны явно использовать ключевое слово struct для объявления структуры. В C++ это не нужно, когда тип определен». См. ссылку для получения дополнительной информации и примеров.

    http://msdn.microsoft.com/en-us/library/64973255%28v=vs.80%29.aspx

    11.10.2011
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..