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

typedef - Typedef без фигурных скобок

Я новичок в C, но что означает этот синтаксис?

typedef Value (*NativeFn)(int argCount, Value* args);

Насколько я понимаю, значение используется здесь для определения типа нового имени. Часть, которую я не понимаю, это (*NativeFn)(int argCount, Value* args);, что означает эта часть?


  • Это указатель на функцию, вы можете изучить его подробнее. При чем тут фигурные скобки? 11.08.2020
  • Это указатель на функцию. Подробнее о них читайте здесь. 11.08.2020
  • Возможный дубликат: указатель функции Typedef?. 11.08.2020
  • Здесь определяется NativeFn (ранее было определено Value msu). Это псевдоним типа для указателя на функцию, принимающую int и указатель на значение и возвращающую значение. 11.08.2020
  • Вас могут смутить фигурные скобки, потому что многие определения типов предназначены для структурных типов. Фигурные скобки являются частью синтаксиса определения struct, а не typedef. 12.08.2020

Ответы:


1

Другие правильно сказали, что это:

typedef Value (*NativeFn)(int argCount, Value* args);

создает имя typedef NativeFn для типа указателя на функцию.

Синтаксис typedef, как и синтаксис объявлений C в целом, может сбивать с толку. Функция typedef фактически была добавлена ​​в язык после того, как был установлен синтаксис объявления, и ее нужно было добавить, не нарушая ничего другого. Решение состояло в том, чтобы рассматривать typedef синтаксически как спецификатор класса хранения (хотя семантически это не так). Спецификаторы класса хранения, отличные от typedef, это extern, static, _Thread_local, auto и register.

Это означает, что вы можете понять объявление typedef, заменив ключевое слово typedef, например, static. Там, где объявление static объявляет объект (или функцию) определенного типа, соответствующее объявление typedef создает определение типа с тем же именем и типом. Итак, это:

static int foo;

создает объект foo типа int (со статической продолжительностью хранения), а это:

typedef int foo;

создает имя типа foo, которое является псевдонимом для типа int.

Итак, если ваша декларация была:

static Value (*NativeFn)(int argCount, Value* args);

он определил бы NativeFn как объект указателя на функцию (с функцией, возвращающей результат типа Value). Замена static на typedef означает, что NativeFn — это имя типа, которое относится к тому же типу указателя на функцию.

Также важно помнить, что typedef не создает новый тип. Он создает новое имя для существующего типа.

11.08.2020

2

Рассмотрим такую ​​запись

Value (int argCount, Value* args)

Он обозначает тип функции, который имеет возвращаемый тип Value и два параметра типа int и Value *.

Идентификатор Value объявлен где-то еще и может быть, например, псевдонимом для типа.

Чтобы ввести псевдоним для типа указателя в тип функции, вы можете написать

typedef Value (*NativeFn)(int argCount, Value* args);

Итак, если у вас есть функция, например

Value some_function(int argCount, Value* args);

то вы можете объявить указатель на эту функцию, используя определение псевдонима typedef следующим образом

NativeFn pointer_to_some_function = some_function; 
11.08.2020

3

Средство typedef используется для создания псевдонимов для типов. Например,

typedef int *iptr;

создает имя iptr как синоним типа int *, поэтому вы можете объявлять указатели, используя

iptr p, q;

вместо того, чтобы писать

int *p, *q;

Синтаксис объявления C немного сложнее, чем думает большинство людей, особенно там, где задействованы указатели. Основные правила:

T *p;            // p is a pointer to T
T *a[N];         // a is an array of pointer to T
T *f();          // f is a function returning pointer to T
T (*a)[N];       // a is a pointer to an array of T
T (*f)();        // f is a pointer to a function returning T
T const *p;      // p is a pointer to const T
const T *p;      // same as above
T * const p;     // p is a const pointer to T

Все может быть сколь угодно сложным — у вас могут быть массивы указателей на функции:

T (*a[N])();

или функции, возвращающие указатели на массивы:

T (*f())[N];

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

typedef Value (*NativeFn)(int, Value*);

делает вещи немного более легкими для понимания.

Это объявление создает NativeFn как синоним указателя типа на функцию, принимающую int и Value * и возвращающую Value.

Предположим, у вас есть функция, определенная как

Value foo( int argcCount, Value *args )
{
  Value result;
  ...
  return result;
}

Если вы хотите создать указатель на эту функцию с именем fptr, вы обычно объявляете ее как

Value (*fptr)(int, Value *) = foo;

Однако приведенное выше объявление typedef позволяет вам написать

NativeFn fptr = foo;

При этом используйте typedef экономно. Проблема в том, что, хотя он может создавать более простые для чтения способы объявления некоторых элементов, он также скрывает некоторую потенциально полезную информацию. Например, несмотря на приведенный выше пример iptr, лучше не скрывать указатели за определениями типов — если кому-то нужно использовать унарный оператор * для p или q, чтобы использовать их правильно, тогда эта информация должна быть быть в декларации этих предметов. Если кому-то когда-нибудь понадобится вызвать объект, на который указывает fptr, ему нужно знать тип возвращаемого значения, количество и типы параметров и т. д., но вся эта информация отсутствует в объявлении, которое использует имя typedef.

11.08.2020

4

Хорошо,

typedef (*NativeFn)(int argCount, Value* args)

означает

NativeFn — это function type(can also be called "a pointer to function" or "function pointer"), который возвращает Value и принимает int и Value * в качестве аргументов.

Если вы не понимаете, почему и как мы должны его использовать, то прочитайте приведенный ниже код, особенно комментарии, вам станет ясно, что означает (*NativeFn)(int argCount, Value* args) и как его использовать:

#include <stdio.h>

// note: "Value" is a type declared earlier
//       for discussions sake we're declaring our own Value type

typedef struct __value {
    int x, y;
} Value;


// now, the following tells us that:
// "NativeFn" is some function type that returns "Value"
typedef Value (*NativeFn)(int argCount, Value* args);


// okay, see how to use "NativeFn"
// for use "NativeFn" we've to declare some function first
// which takes two arguments same as "NativeFn" and return "Value"
Value someFun(int argCount, Value* args) {
    // do something argCount and args
    // at last it should return some "Value" type
    Value v = {2, 3};
    return v;
}

int main() {
    // now its time to use "NativeFn"
    NativeFn fun;

    fun = someFun; // notice we can use fun as a variable and assign a
    // function to it, which must take arguments same as "NativeFn" and returns "Value" type

    Value input = {10, 12};
    
    Value output = fun(1, &input); // note, we're calling "fun", not "someFun"

    // it'll output 2, 3, cause we're returning Value v = {2, 3} from "someFun"
    printf("(x, y): %d, %d\n", output.x, output.y);
    
    return 0;
}

Если у вас есть вопросы, задавайте их в комментариях...

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

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

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

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

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

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

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

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