LINUX.ORG.RU

extern C и ключевые слова C++

 ,


0

2

У меня тут такой мутантец:

extern "C" {
void BLABLA_IRQHandler(void) {
// some C code
}
}

// some C++ code

Там где C++ codе был какой-то код, который, например, делал вот так:

BlaBla *bla = reinterpret_cast<BlaBla*>(blabla);

Потом этот код методом Копи и Пэйста был перенесен в BLABLA_IRQHandler и он по какой-то причине работает. Мне не париться и оставить как есть или переписать так:

extern "C" {
void BLABLA_IRQHandler(void) {
    BlaBla *bla = (BlaBla*)(blabla);
}
}

// some C++ code

? Весь файл компилируется g++. Я так понял это работает, потому что reinterpret_cast - это ключевое слово, поэтому раз компилятор g++, то оно и работает, даже в части extern «C». Я прав? Это вообще надежно, что так работает?

extern «C» влияет только на описание глобальных символов

mittorn ★★★★★
()

Но я бы так сделал:

extern "C" void BLABLA_IRQHandler(void);
void BLABLA_IRQHandler(void)
{
    BlaBla *bla = (BlaBla*)(blabla);
}

mittorn ★★★★★
()
Ответ на: комментарий от thunar

Т.е. это только для demangling? А что по поводу например:

void f(void); // in C this takes no parameters
void f(); // in C this takes any number of parameters
void f(); // in C++ this takes no parameters

В таком примере:

extern "C" {
void f();
}

Сколько параметров принимает f()?

dissident ★★
() автор топика
Ответ на: комментарий от dissident

void f(); // in C this takes any number of parameters

После появления в C эллипса (...), юзать как функцию с неопределенным количеством параметров это уже лет 30 как стало плохим тоном и сыпет предупреждениями.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Ты путаешь функции с неизвестным количеством параметров с функциями с произвольным количеством параметров?

anonymous
()

https://en.cppreference.com/w/cpp/language/reinterpret_cast

Если кратко, то reinterpret_cast говорит «я гарантирую, что к куску памяти по указателю blabla можно обращаться как к указателю типа BlaBla, атвичаю, ничего не проверяй, тупо делай». То есть так делать можно, но нужно смотреть на бинарную совместимость типов и layout.

Вот что точно не должно быть в irqh, так это dynamic_cast, а все остальные _cast можно.

whoami
()
Последнее исправление: whoami (всего исправлений: 2)
Ответ на: комментарий от anonymous

Ты путаешь функции с неизвестным количеством параметров с функциями с произвольным количеством параметров?

Это одно и тоже. Разница только в том, что можно вначале указать известное, но ведь не обязательно.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Это ты утверждаешь, а я только отказываюсь принимать твоё утверждение на веру. Так что вперёд, доказывай, что это одно и то же.

anonymous
()
Ответ на: комментарий от whoami

Если кратко, то reinterpret_cast говорит «я гарантирую, что к куску памяти по указателю blabla можно обращаться как к указателю типа BlaBla, атвичаю, ничего не проверяй, тупо делай». То есть так делать можно, но нужно смотреть на бинарную совместимость типов и layout.

Я про то, что reinterpret_cast - ключевое слово C++, а не C, отсюда и вопрос: корректно ли в контексте extern «C» использовать конструкции языка C++ (весь файл компилируется g++, а не gcc).

Вот что точно не должно быть в irqh, так это dynamic_cast, а все остальные _cast можно.

А что такое страшное в dynamic_cast, что его нельзя использовать в irqh? RTTI? Что в нем такого противоirqhного?

dissident ★★
() автор топика
Ответ на: комментарий от anonymous

Это ты утверждаешь,

Так я и доказал. А вы всё как обычно в стиле анонима с ЛОРа, тупо талдычите, что нет, не так, но у наши приборы мы вам не покажем.

vodz ★★★★★
()
Ответ на: комментарий от vodz

После появления в C эллипса (…), юзать как функцию с неопределенным количеством параметров это уже лет 30 как стало плохим тоном и сыпет предупреждениями.

Я к тому, что f(void) писать в контексте extern «C» или f() если файл компилируется g++, а надо сказать, что функция не принимает параметров? Ну т.е., например, оно и так и этак линкуется, интересно просто, как это кошерно надо делать.

dissident ★★
() автор топика
Ответ на: комментарий от dissident

void f(); // in C this takes any number of parameters

Не any, а unknown.

anonymous
()
Ответ на: комментарий от vodz

А тождественность доказана не была, было только заявлено, что это одно и то же.

anonymous
()
Ответ на: комментарий от dissident

как это кошерно надо делать.

Так я вам и говорю, что уже 30 лет так некошерно делать вообще. Никогда не было возможности юзать функции с совсем непонятным списком параметров, всё равно должен быть хоть один параметр, который флагами (как ioctl и open) или форматом как printf расскажет как собственно функция распознает эти параметры. В старом C не было такого синтаксиса, но уже давно нет необходимости в такой декларации как ().

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 2)
Ответ на: комментарий от dissident

Файл конпелируется как C++, значит можно

Harald ★★★★★
()
Ответ на: комментарий от vodz

Так я вам и говорю, что уже 30 лет так некошерно делать вообще

Да я понял, понял, я не буду так делать, честно!

Я просто про то, что в крестах пустые скобки, значит, нет параметров. А мой IRQHandler не принимает параметров, линкуется с каким-то там ASM startup кодом, ну и должен быть extern «C». Но файл я компелирую g++. А знчит по идее могу как extern «C» { void IRQHandler(); } так и extern «C» { void IRQHandler(void); } и Б-г его знает, как кошерно.

Но мне в принципе объяснили, что раз файл компелируется g++, то и синтаксис унутре будет C++. Но я почему-то по привычке в секции extern «C» продолжаю писать void IRQHandler(void), а не void IRQHandler(), а за секцией extern «C» продолжаю писать void ICodeCppForFood(/* no void! */) и не знаю мой код блажен и чист или неряшлив и грязен.

PS Просто я первый раз такого уродца вижу. Я так понял во всяким embedded такие C-C++ уродцы - норма. Часть файлов gcc собирается, часть g++, причем если все собрать g++ то не работает из-за, видимо, каких-то ASM кусков (FreeRTOS, например, если g++ собрать (после некоторых минимальных манипуляций) тупо не работает).

dissident ★★
() автор топика
Ответ на: комментарий от dissident

void f() и void f(void) - это одно и то же. в первом случае ты неявно указываешь, что функция не принимает параметры (пустой список параметров), во втором случае ты это делаешь явно, вот и вся разница.

void f(void) - это старая запись когда неявная форма не поддерживалась, потом (лет 20-30 назад) добавили сахарок в виде неявной формы. ну это для си89 наверное.

gcc - это компилятор си, g++ - это компилятор с++. если ты компилируешь код на си, то надо использовать gcc, если с++, то g++.

anonymous
()
Ответ на: комментарий от anonymous

gcc - это компилятор си, g++ - это компилятор с++. если ты компилируешь код на си, то надо использовать gcc, если с++, то g++.

Я же говорю, у меня мутант. FreeRTOS, например, компилируется gcc, часть кода компилируется g++. Потом все это линкуется вместе. В той части кода, которая компилируется g++ присутствуют куски extern «C». Мой вопрос касался (и в принципе до сих пор касается): какой синтаксис кошерно использовать в файлах компилируемых g++ в их секциях extern «C», там использовать синтаксис C или C++? Практика и здравый смысл показывают, что использовать конструкции C++ в кусках extern «C» можно (как, например, reinterpret_cast), вопрос о стиле.

dissident ★★
() автор топика
Ответ на: комментарий от dissident

Деманглинг и соглашения по передаче параметров. Синтаксис внутри С++.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)
Ответ на: комментарий от dissident

Я же говорю, у меня мутант.

не надо было бухать.

g++ компилирует код на с++, gcc компилирует код на си. ну ты если го будешь компилировать, ты же будешь использовать компилятор го, так ведь? ну и тут так же, для того чтобы откомпилировать код на с++ нужен компилятор с++.

линкуется всё вместе наверное как си-код, поэтому и extern «C», чтобы с++ символы слинковались как си символы.

в с++ надо использовать конструкции с++. идиоматическое преобразование типов в с++ - это reinterpret_cast или dynamic_cast или static_cast. выражение вида (type)(val) - это си-стайл каст который используется для преобразования типов в си.

anonymous
()
Ответ на: комментарий от dissident

я понял что тебя смущает.

В таком примере:

extern "C" {
void f();
}

Сколько параметров принимает f()?

ноль, потому что это код на с++. в си не надо было бы указывать extern «C» потому что код и так уже на си.

f() принимающий неопределённое количество аргументов - это для совместимости с k&r си, забудь про это, это фича из си до стандартизации, в си коде пиши f(void) в с++ коде пиши f().

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

anonymous
()
Ответ на: комментарий от anonymous

anonymous и все, спасибо за разъяснения!

dissident ★★
() автор топика

Вот какому вменяемому человеку придет в голову писать на этом говноуродстве, называемом C++?

reinterpret_cast<void*>(foo) - это же писать можно задолбаться даже, вместо (void)foo

lovesan ★★
()
Ответ на: комментарий от lovesan

reinterpret_cast<void*>(foo) - это же писать можно задолбаться даже, вместо (void*)foo

Просто не соберётся твой код, в зависимости от опций компиляции:

https://gcc.godbolt.org/z/e58eMK

fsb4000 ★★★★★
()
Ответ на: комментарий от lovesan

уродстве

reinterpret_cast<void*>(foo)

Это специально сделано, чтобы такие некрасивые касты выглядели уродливо. Что уродливо, то должно выглядеть уродливо.

anonymous
()
Ответ на: комментарий от lovesan

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

Elyas ★★★★★
()
Ответ на: комментарий от Elyas

Единственный смысл писать на низкоуровневом языке это указатели, их арифметика, байтодрочерство и прямой доступ к памяти. Что вобщем доказывает что плюсы и в это нормально не могут. А для высокоуровневых вещей есть нормальные языки. Вобщем плюсы это такая вот пятая нога у коровы.

lovesan ★★
()
Ответ на: комментарий от lovesan

это делали для упрощения поиска по коду

anonymous
()
Ответ на: комментарий от dissident

какая разница сколько там параметров, если и в С и в С++ вызывающий код чистит стэк

anonymous
()
Ответ на: комментарий от lovesan

Вот какому вменяемому человеку придет в голову писать на этом говноуродстве, называемом C++?

Не скажи, эти многословные касты много читаемей Cшных, например:

WRITE_REG(((DMA_Stream_TypeDef*)((uint32_t)((uint32_t)DMAx + STREAM_OFFSET_TAB[Stream])))->M0AR, SrcAddress);

Что тут в этой каше куда кастится непонятно.

dissident ★★
() автор топика
Ответ на: комментарий от lovesan

Вобщем плюсы это такая вот пятая нога у коровы.

Без плюсов получается свалка из функций. Ты GTK использовал на C? Попробуй, незабываемо!

dissident ★★
() автор топика
Ответ на: комментарий от lovesan

А кто ещё, кроме плюсов, имеет настолько хорошие оптимизирующие компиляторы и стандарт, который достаточно хорошо определяет язык (и позволяет для него такие компиляторы писать)?

На мой взгляд, неплохим субъективным критерием «хорошести» оптимизатора можно назвать неожиданное поведение (не догадался бы, что из такого исходника можно сгенерировать такой код) при UB. Какие ещё языки обладают похожими качествами?

kmeaw ★★★
()
Ответ на: комментарий от lovesan

А можете продемонстрировать фрагмент кода и какую-нибудь реализацию Common Lisp, которая скомпилирует этот фрагмент так, что результат из-за оптимизаций покажется неожиданным?

Лет 15 назад я смотрел на результат работы SBCL, и ни разу с таким не сталкивался. Да, там попадались интересные приёмы (использование int3, например), но их появление было обусловленно не оптимизациями, а особенностями устройства конкретных структур данных в SBCL, которые не менялись от программы к программе. Интересно, изменилось ли в этом плане что-то с тех пор?

kmeaw ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.