Страницы

Поиск по вопросам

Показаны сообщения с ярлыком typedef. Показать все сообщения
Показаны сообщения с ярлыком typedef. Показать все сообщения

вторник, 31 марта 2020 г.

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

#c #typedef


Допустим, есть такой код:

typedef int i32;


Как узнать, был ли тип i32 уже объявлен ранее? Т. е. что-то типа #ifdef только для
typedef.
    


Ответы

Ответ 1



Никак не узнать. Если дальновидный автор кода предвидит необходимость такой проверки в будущем, он обычно сопровождает определения типов определением дополнительного макро. Так, например, стандартный заголовочный файл содержит определение макро __bool_true_false_are_defined со значением 1.

Ответ 2



Есть метод двойной компиляции, знаю как в Linux через Makefile это делать. Сначала компилируется простой файл с typedef. Затем проверяется код ошибки компиляции, и задаётся #define TYPEREDEFINIED. Makefile : main.o : main.c main.h ..TAB..: if gcc checktypedef.c &> /dev/null ; then ; else OPTIONFORGCC = -DTYPEREDEFINIED ; fi ..TAB..: gcc OPTIONFORGCC main.c .. checktypedef.c : # include <все заголовки из main> typedef unsigned char BYTE ; main.c : # include <все заголовки> # ifdef TYPEREDEFINIED # error Опять! # endif

Ответ 3



Возможно обьявить все используемые хеадеры в одном файле test.c например, потом: gcc -E test.c | grep "int32my" и смотрим результат :)

среда, 26 февраля 2020 г.

Непонятный синтаксис с двумя именами в typedef

#c #typedef #union


typedef union {  
    char word[16];  
    uint32_t chunk[4];  
    uint64_t big_chunk[2];  
} Word, *PWord;   // <-- Что означают эти два имени?

    


Ответы

Ответ 1



Да хоть с десятью именами. Как и [почти] любое объявление в С, typedef-объявление может объявлять несколько идентификаторов сразу const int a, *b, *const *c, d[5], e(void); // эквивалентно const int a; const int *b; const int *const *c; const int d[5]; const int e(void); Точно так же typedef int a, *b, *const *c, d[5], e(void); // эквивалентно typedef int a; typedef int *b; typedef int *const *c; typedef int d[5]; typedef int e(void); Именно это и используется в вашем объявлении. То, что в объявлении фигурирует union, тут никакой принципиальной роли не играет. Если бы у вашего union был указан тэг (скажем, W), то можно было разбить ваше объявление на три отдельных объявления union W { char word[16]; uint32_t chunk[4]; uint64_t big_chunk[2]; }; typedef union W Word; typedef union W *PWord;

Ответ 2



Объявлены: Word - тип объединения, PWord - тип указателя на объединение. Вас это интересовало?

вторник, 25 февраля 2020 г.

Как работает typedef в этом коде?

#функции #typedef #cpp


#include 
using namespace std;

typedef int (*func)(int a, int b);

int call_func(int a, int b)
{
    return a + b;
}

void function(int a, int b, func f);

int main ()
{

    function(5, 2, &call_func);
    system("pause");
}

void function(int a, int b, func f)
{
    int sum = (*f)(a, b);
    std::cout << "Sum = " << sum << std::endl;
}

typedef вводит новое имя для типа, и примеры вида typedef int int32 думаю понятны
любому. Ну а что с typedef int (*func)(int a, int b); в этом коде, он же должен вместо
func f подставить int (int a, int b) f, а подставляет int f(int a, int b), хотя я не
только это не понимаю, а и то, откуда он знает что заменять нужно func, ведь это неполный
тип или имя. Описание typedef в интернете заканчиваются на typedef int int32 или же
просто с примером структур и функций или ещё каких сложных типов, но без объяснений.
Я уже не знаю что думать, с дефайном было как-то проще.    


Ответы

Ответ 1



typedef -- не просто текстовая подстановка. Он работает следующим образом: если X -- имя typedef-типа, объявление переменной X x; работает как будто бы на этом месте стоит описание типа в typedef, где X заменено на x. То есть typedef int (*func)(int a, int b); func f; работает как int (* /*было func, стало*/ f )(int a, int b);

четверг, 26 декабря 2019 г.

typedef в лямбда-выражениях

#visual_cpp #typedef #cpp11 #cpp #lambda


Недавно обнаружил странный "баг" или "недофичу" в реализации лямбда-функций vs2010:
template< typename Anc >
class A : public Anc{
  //
  typedef SomeJobClassSpec  JOB;
  //
  void something(){
    std::for_each(
      Some.begin(), Some.end(), []( SOME&x ){
        new JOB::TASK( ... ); // ошибка: JOB не определен!!!
      }
    );
  }
};

Решение:
template< typename Anc >
class A : public Anc{
  //
  typedef SomeJobClassSpec  JOB;
  //
  void something(){
    std::for_each(
      Some.begin(), Some.end(), []( SOME&x ){
        typedef JOB _JOB;
        //
        new _JOB::TASK( ... ); // OK!!!
      }
    );
  }
};

Выходит, typedef в лямбдах видит несколько больше?    


Ответы

Ответ 1



Это, должно быть, баг VS 2010. У gcc-4.7.2 проблем с похожим кодом нету: http://ideone.com/Pi6slP.

суббота, 7 декабря 2019 г.

Способ уменьшения ошибок в программе

#c #typedef


В процессе изучения появилась такая мысль использования typedef:

#include

typedef int height;
typedef int width;
typedef int mul;

mul sq(height,width);

int main(){
        width h=5;/*or 'int' or other type*/
        width w=17;
        printf("%d\n",sq(h,w));
}
mul sq(height h,width w){
        return h * w;
}


но фишка не удалась. И я, как и следовало ожидать, получил не то что хотел.Я понял,
что у меня в примере функция аналогична такой:

    int sq(int h,int w){
        return h * w;
}


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


Ответы

Ответ 1



В языке С создание пользовательских типов, способных нести произвольные данные, возможно только через определение новых struct-типов, array-типов или enum-типов. Enum-типы в С всегда целочисленны и свободно конвертируемы между собой, что делает их непригодными для решения данной задачи. Array-типы подходят плохо, имеют свойство деградировать до указателей и являются некопируемыми, что делает их непригодными для решения данной задачи тоже. Остаются только struct-типы. Придется заворачивать значения в struct-типы с одним полем. Это, однако, сделает код довольно перегруженным повторяющимися синтаксическими деталями. Составные литералы и, возможно, _Generic помогут сделать код более элегантным, но превратить С в С++ все равно не смогут. Так что вопрос в том, насколько сильно вам этого хочется. #include typedef struct { int value; } height; typedef struct { int value; } width; typedef struct { int value; } area; area sq(height h, width w) { return (area) { h.value * w.value }; } int main() { width h = { 5 }; width w = { 17 }; height h2 = { 5 }; // printf("%d\n", sq(h, w).value); printf("%d\n", sq(h2, w).value); }

среда, 27 ноября 2019 г.

Зачем typedef объвлять с одним и тем же типом

#c #структуры #объявление #typedef


Наверно какие-то C-шные ухищрения. Навроде их классов. Вроде бы и объявление тут
уже есть. Может поэтому? Вот такая строка например (из OpenCV):

typedef struct CvFileStorage    CvFileStorage;


Зачем же так писать? Не нашел никак, сходу, ответ на это. Когда-то (несколько лет
назад), помню что читал об этом. Тогда чистый C был в моде наверное, а сейчас такое
позабыто получается. Еще подобное видел в коде от Windows CE6 и др. Это запомнил:),
а для чего нужно не помню никак. Если еще какие-то доп. куски кода надо привести, то
скажите. Эта строка стоит перед структурой, которая у себя где-то в поле использует
тип из этого typedef-а. Но зачем так писать, а не просто объявить его? Спасибо.
    


Ответы

Ответ 1



Имеется по крайней мере две веские причины объявить этот typedef. typedef struct CvFileStorage CvFileStorage; Первая причина заключается в том, что в C программах вы должны указывать ключевые слова struct или enum перед именем структуры или перечисления. Это выглядит обременительно при вводе кода. Очень часто программисты забывают указать эти слова, что приводит к появлению ошибки компиляции. Поэтому этот typedef упрощает жизнь программистам, позволяя им не писать эти ключевые слова перед именем структуры или перечисления. Вторая причина состоит в том, что имена структур и другие идентификаторы находятся в различных пространствах имен. Поэтому одно и то же имя можно использовать для объявления структуры и обычной переменной. Например, следующий фрагмент кода является корректным struct CvFileStorage { //... }; int CvFileStorage; В этом фрагменте кода объявляется структура с именем CvFileStorage и переменная типа int с тем же самым именем. Эти объявления не конфликтует друг с другом, так как, как уже было написано, перед именем структуры обязательно должно следовать ключевое слово struct . В C вы можете записать, к примеру struct CvFileStorage { int CvFileStorage; } CvFileStorage; Это объявление корректно, так как эти три совпадающих идентификаторs находятся в различных пространствах имен. Однако это может вводить в заблуждение читающих код, так как если программист по ошибке опустит ключевое слово struct перед именем структуры, то может оказаться, что код по-прежнему с точки зрения синтаксиса языка будет корректным, хотя на самом деле имелась в виду структура, а не переменная с таким же именем. Например, в данном выражении программист по невнимательности забыл указать ключевое слово struct, и тем не менее получил корректное выражение, так как имеется переменная с таким же именем sizeof( CvFileStorage ) Чтобы избежать такой путаницы также целесообразно резервировать это имя без ключевого слова struct для имени структуры, используя typedef.. В С++ ключевое слово struct можно опускать при обращении к структуре. Тогда возникает вопрос: а как быть с тем, что в C можно объявлять переменную или функцию с таким же имеенем как имя структуры? Этот вопрос решается следующим образом: имя переменной или имя функции скрывает объявление структуры с тем же самым именем. Поэтому при обращении к структуре надо указывать уточненное имя. Например, struct CvFileStorage { //... }; void CvFileStorage(); В этом фрагменте кода объявление функции скрывает объявление одноименной структуры. Поэтому если, например, вы хотите объявить объект этой структуры, то надо будет указывать уточненное имя структуры. struct CvFileStorage obj; Или, например, можно написать такие объявления struct CvFileStorage { //... }; void CvFileStorage( struct CvFileStorage ); Эти имена не будут конфликтовать друг с другом, так как для структуры используется ее уточненное имя.

Ответ 2



В с++ если нужно объявить переменную типа структуры, нужно просто написать имя типа и переменную. В чистом си это не так. И нужно всегда писать struct. Это все потому, что типы для структур и остальные типы как бы находятся в разных областях видимости. Но так как программисты существа ленивые, то лучше один наз написать typedef struct CvFileStorage CvFileStorage; и потом не задумываться, почему оно не компилируется (потому что забыли struct) или почему оно работает как то странно (потому что забыли struct, а кто то объявил свой тип не структуру с таким же именем). Но часто пишут ещё интереснее: typedef struct { // тут объявление структры } struct_name; В этом случае создается сразу все так, как привычно в обычном с++.

Ответ 3



Без этого typedef при любом упоминании структуры CvFileStorage надо писать полностью: struct CvFileStorage cv; void func(struct CvFileStorage* cv); и так далее. При наличии объявления typedef слово struct можно выбрасывать: CvFileStorage cv; void func(CvFileStorage* cv);

суббота, 8 июня 2019 г.

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

Допустим, есть такой код:
typedef int i32;
Как узнать, был ли тип i32 уже объявлен ранее? Т. е. что-то типа #ifdef только для typedef


Ответ

Никак не узнать.
Если дальновидный автор кода предвидит необходимость такой проверки в будущем, он обычно сопровождает определения типов определением дополнительного макро. Так, например, стандартный заголовочный файл содержит определение макро __bool_true_false_are_defined со значением 1

вторник, 14 мая 2019 г.

Как работает typedef в этом коде?

#include using namespace std;
typedef int (*func)(int a, int b);
int call_func(int a, int b) { return a + b; }
void function(int a, int b, func f);
int main () {
function(5, 2, &call_func); system("pause"); }
void function(int a, int b, func f) { int sum = (*f)(a, b); std::cout << "Sum = " << sum << std::endl; } typedef вводит новое имя для типа, и примеры вида typedef int int32 думаю понятны любому. Ну а что с typedef int (*func)(int a, int b); в этом коде, он же должен вместо func f подставить int (int a, int b) f, а подставляет int f(int a, int b), хотя я не только это не понимаю, а и то, откуда он знает что заменять нужно func, ведь это неполный тип или имя. Описание typedef в интернете заканчиваются на typedef int int32 или же просто с примером структур и функций или ещё каких сложных типов, но без объяснений. Я уже не знаю что думать, с дефайном было как-то проще.


Ответ

typedef -- не просто текстовая подстановка. Он работает следующим образом: если X -- имя typedef-типа, объявление переменной X x; работает как будто бы на этом месте стоит описание типа в typedef, где X заменено на x То есть typedef int (*func)(int a, int b); func f; работает как int (* /*было func, стало*/ f )(int a, int b);

четверг, 29 ноября 2018 г.

typedef в лямбда-выражениях

Недавно обнаружил странный "баг" или "недофичу" в реализации лямбда-функций vs2010: template< typename Anc > class A : public Anc{ // typedef SomeJobClassSpec JOB; // void something(){ std::for_each( Some.begin(), Some.end(), []( SOME&x ){ new JOB::TASK( ... ); // ошибка: JOB не определен!!! } ); } }; Решение: template< typename Anc > class A : public Anc{ // typedef SomeJobClassSpec JOB; // void something(){ std::for_each( Some.begin(), Some.end(), []( SOME&x ){ typedef JOB _JOB; // new _JOB::TASK( ... ); // OK!!! } ); } }; Выходит, typedef в лямбдах видит несколько больше?


Ответ

Это, должно быть, баг VS 2010. У gcc-4.7.2 проблем с похожим кодом нету: http://ideone.com/Pi6slP

среда, 3 октября 2018 г.

Зачем typedef объвлять с одним и тем же типом

Наверно какие-то C-шные ухищрения. Навроде их классов. Вроде бы и объявление тут уже есть. Может поэтому? Вот такая строка например (из OpenCV):
typedef struct CvFileStorage CvFileStorage;
Зачем же так писать? Не нашел никак, сходу, ответ на это. Когда-то (несколько лет назад), помню что читал об этом. Тогда чистый C был в моде наверное, а сейчас такое позабыто получается. Еще подобное видел в коде от Windows CE6 и др. Это запомнил:), а для чего нужно не помню никак. Если еще какие-то доп. куски кода надо привести, то скажите. Эта строка стоит перед структурой, которая у себя где-то в поле использует тип из этого typedef-а. Но зачем так писать, а не просто объявить его? Спасибо.


Ответ

Имеется по крайней мере две веские причины объявить этот typedef.
typedef struct CvFileStorage CvFileStorage;
Первая причина заключается в том, что в C программах вы должны указывать ключевые слова struct или enum перед именем структуры или перечисления. Это выглядит обременительно при вводе кода. Очень часто программисты забывают указать эти слова, что приводит к появлению ошибки компиляции. Поэтому этот typedef упрощает жизнь программистам, позволяя им не писать эти ключевые слова перед именем структуры или перечисления.
Вторая причина состоит в том, что имена структур и другие идентификаторы находятся в различных пространствах имен. Поэтому одно и то же имя можно использовать для объявления структуры и обычной переменной. Например, следующий фрагмент кода является корректным
struct CvFileStorage { //... };
int CvFileStorage;
В этом фрагменте кода объявляется структура с именем CvFileStorage и переменная типа int с тем же самым именем. Эти объявления не конфликтует друг с другом, так как, как уже было написано, перед именем структуры обязательно должно следовать ключевое слово struct .
В C вы можете записать, к примеру
struct CvFileStorage { int CvFileStorage; } CvFileStorage;
Это объявление корректно, так как эти три совпадающих идентификаторs находятся в различных пространствах имен.
Однако это может вводить в заблуждение читающих код, так как если программист по ошибке опустит ключевое слово struct перед именем структуры, то может оказаться, что код по-прежнему с точки зрения синтаксиса языка будет корректным, хотя на самом деле имелась в виду структура, а не переменная с таким же именем.
Например, в данном выражении программист по невнимательности забыл указать ключевое слово struct, и тем не менее получил корректное выражение, так как имеется переменная с таким же именем
sizeof( CvFileStorage )
Чтобы избежать такой путаницы также целесообразно резервировать это имя без ключевого слова struct для имени структуры, используя typedef..
В С++ ключевое слово struct можно опускать при обращении к структуре. Тогда возникает вопрос: а как быть с тем, что в C можно объявлять переменную или функцию с таким же имеенем как имя структуры?
Этот вопрос решается следующим образом: имя переменной или имя функции скрывает объявление структуры с тем же самым именем. Поэтому при обращении к структуре надо указывать уточненное имя.
Например,
struct CvFileStorage { //... };
void CvFileStorage();
В этом фрагменте кода объявление функции скрывает объявление одноименной структуры. Поэтому если, например, вы хотите объявить объект этой структуры, то надо будет указывать уточненное имя структуры.
struct CvFileStorage obj;
Или, например, можно написать такие объявления
struct CvFileStorage { //... };
void CvFileStorage( struct CvFileStorage );
Эти имена не будут конфликтовать друг с другом, так как для структуры используется ее уточненное имя.