Кастинг указателя функции к другому типу

Проблема решена:

import React, { Component } from  'react';
import $ from 'jquery';
import timepicker from 'timepicker'

class TimePicker extends Component {
    componentDidMount(){
        this.initDatepicker();
      }

  initDatepicker(){
    $(this.refs.timepicker).timepicker();
  }

  handleChange = (e) => {
    console.log(e.currentTarget.value)
  }

  render(){
    return (
      <div>
        <input className='timepicker' type='text' ref='timepicker' onBlur={e => this.handleChange(e)} />
      </div>
    )
  }

}

export default TimePicker;
81
задан Community 23 May 2017 в 11:54
поделиться

5 ответов

Что касается стандарта C, если Вы бросаете указатель функции к указателю функции другого типа и затем называете это, это неопределенное поведение . См. (информативное) Приложение J.2:

поведение не определено при следующих обстоятельствах:

  • указатель А используется для вызывания функции, тип которой не совместим с указанным Раздел типа (6.3.2.3).

6.3.2.3, чтения абзаца 8:

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

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

определение совместимый является несколько сложным. Это может быть найдено в разделе 6.7.5.3, абзаце 15:

, Чтобы два функциональных типа были совместимы, оба должны указать, что совместимый возврат вводит <глоток> 127 .

, Кроме того, списки типов параметра, если и присутствуют, должны согласиться в количестве параметров и используемый из разделителя замещающего знака; соответствующие параметры должны иметь совместимые типы. Если один тип будет иметь список типов параметра, и другой тип указан функциональным оператором объявления, который не является частью функционального определения, и это содержит пустой список идентификаторов, то список параметров не должен иметь разделителя замещающего знака, и тип каждого параметра должен быть совместим с типом, который следует из приложения продвижений параметра по умолчанию. Если один тип будет иметь список типов параметра, и другой тип указан функциональным определением, которое содержит (возможно пустой) список идентификаторов, то оба должны согласиться в количестве параметров, и тип каждого опытного параметра должен быть совместим с типом, который следует из приложения продвижений параметра по умолчанию типу соответствующего идентификатора. (В определении соответствия типов и составного типа, каждый параметр, объявленный с функциональным или типом массива, взят в качестве наличия скорректированного типа, и каждый параметр, объявленный с квалифицированным типом, взят в качестве наличия неполной версии его заявленного типа.)

127), Если оба функциональных типа являются ‘‘old style’’, типы параметра не сравнены.

правила для определения, совместимы ли два типа, описаны в разделе 6.2.7, и я не заключу им в кавычки здесь, так как они довольно длинны, но можно считать их на проект стандарта C99 (PDF) .

соответствующее правило здесь находится в разделе 6.7.5.1, абзаце 2:

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

Следовательно, начиная с void* не совместим с struct my_struct*, указатель функции типа void (*)(void*) не совместим с указателем функции типа void (*)(struct my_struct*), таким образом, этот кастинг указателей функции является технически неопределенным поведением.

На практике, тем не менее, можно безопасно сойти с рук кастинг указателей функции в некоторых случаях. В x86 соглашении о вызовах аргументы продвинуты на стеке, и все указатели являются тем же размером (4 байта в x86 или 8 байтов в x86_64). Раскритиковывание указателя функции кипит к продвижению аргументов на стеке и выполнении косвенного перехода к цели указателя функции, и нет, очевидно, никакого понятия типов на уровне машинного кода.

Вещи Вы определенно не можете делать:

  • Бросок между указателями функции различных соглашений о вызовах. Вы испортите стек и в лучшем случае катастрофический отказ, в худшем случае, успешно выполнитесь тихо с огромной зияющей дырой в системе безопасности. В программировании Windows Вы часто раздаете указатели функции. Win32 ожидает, что все функции обратного вызова будут использовать stdcall соглашение о вызовах (который макросы CALLBACK, PASCAL, и WINAPI все разворачивают до). При передаче указателя функции, который использует стандарт C соглашение о вызовах (cdecl), вредность закончится.
  • В C++, брошенном между указателями функции членства класса и указателями регулярной функции. Это часто сбивает с толку новичков C++. Функции членства класса имеют скрытое this параметр, и если Вы бросаете функцию членства к регулярной функции, нет никакого this объект использовать, и снова, много вредности закончится.

Другая плохая идея, которая могла бы иногда работать, но является также неопределенным поведением:

  • Кастинг между указателями функции и регулярными указателями (например, кастинг void (*)(void) к void*). Указатели функции являются не обязательно тем же размером как регулярные указатели, с тех пор на некоторой архитектуре они могли бы содержать дополнительную контекстную информацию. Это будет, вероятно, работать хорошо над x86, но помнить, что это - неопределенное поведение.
117
ответ дан ivaigult 24 November 2019 в 09:36
поделиться

Точка действительно не, можете ли Вы. Тривиальное решение

void my_callback_function(struct my_struct* arg);
void my_callback_helper(void* pv)
{
    my_callback_function((struct my_struct*)pv);
}
do_stuff(&my_callback_helper);

А, хороший компилятор только сгенерирует код для my_callback_helper, если это будет действительно необходимо, в этом случае Вы радовались бы, что это сделало.

7
ответ дан MSalters 24 November 2019 в 09:36
поделиться

У Вас есть совместимый функциональный тип, если тип возврата и типы параметра совместимы - в основном (это более сложно в действительности :)). Совместимость совпадает с "тем же типом", просто более слабым, чтобы позволить иметь различные типы, но все еще иметь некоторую форму высказывания "этих типов, почти то же". В C89, например, две структуры были совместимы, если они были в других отношениях идентичны, но просто их имя отличалось. C99, кажется, изменили это. Заключая в кавычки из c документ объяснения (настоятельно рекомендованное чтение, btw!):

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

, Который сказал - да строго, это - неопределенное поведение, потому что Ваши do_stuff функционируют, или кто-то еще вызовет Вашу функцию с указателем функции, имеющим void* как параметр, но Ваша функция имеет несовместимый параметр. Но тем не менее, я ожидаю, что все компиляторы скомпилируют и выполнят его без стенания. Но можно сделать инструмент для очистки при наличии другой функции, берущей void* (и регистрирующийся, что как функция обратного вызова), который просто вызовет фактическую функцию затем.

5
ответ дан Johannes Schaub - litb 24 November 2019 в 09:36
поделиться

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

я надеюсь, что могу сделать это более ясным путем показа того, что не работало бы:

int my_number = 14;
do_stuff((void (*)(void*)) &my_callback_function, &my_number);
// my_callback_function will try to access int as struct my_struct
// and go nuts

или...

void another_callback_function(struct my_struct* arg, int arg2) { something }
do_stuff((void (*)(void*)) &another_callback_function, NULL);
// another_callback_function will look for non-existing second argument
// on the stack and go nuts

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

4
ответ дан che 24 November 2019 в 09:36
поделиться

Если Вы думаете о способе, которым вызовы функции работают в C/C++, они продвигают определенные объекты на стеке, переходе к новому участку кода, выполняют, то выталкивают стек по возврату. Если Ваши указатели функции описывают функции с тем же типом возврата и тем же числом/размером аргументов, необходимо быть хорошо.

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

0
ответ дан Steve Rowe 24 November 2019 в 09:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: