LINUX.ORG.RU

Валидное ли это c-выражение?

 ,


0

4

subj:

void foo(char *a, char b, char c) {
	(a ? *a : b) = c;
}

GCC съедает без проблем, SDCC ругается что слева не lvalue.

upd. Под плюсами корректное, под си нет.

upd#2, solution.

★★★★★

Последнее исправление: thunar (всего исправлений: 5)
Ответ на: комментарий от MKuznetsov

Косвенно оно возвращает c в *a если там не нулевой указатель.
Сделано это чтобы можно было инициализировать

int &r = cond ? a : b;
в c++, в c соответсвенно такой необходимости нет и выражение невалидно

mittorn ★★★★★
()
Последнее исправление: mittorn (всего исправлений: 1)

Этот фокус нужно делать так:

#include <iostream>

int main()
{
    int* a = new int;
    *a = 4;
    
    // int* a = nullptr;

    int b = 5;

    *(a ? a : &b) = 10;

    if (a)
        std::cout << "a=" << *a << std::endl; 
        
    std::cout << "b=" << b << std::endl;
}
rumgot ★★★★★
()

(a ? *a : b) = c;

А в чем смысл этого выражения? Ну то есть если a=NULL, то измениться должна локальная копия b?

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

Тут важен сам механизм присваиваивания. Для C оно будет выглядеть так же. И для char тоже. Ты по сути скажи что-то лучше. А то нашёл тоже, к чему докопаться, смехота.

rumgot ★★★★★
()

не надо так писать, даже если это валидное выражение.

#define SET_A(a, b, c) ((__builtin_types_compatible_p(typeof(a), char*) && (a)) ? (*(char*)(a) = c) : (b = c))

не претендую ни на что, но все-таки понятнее вашего и ф-цию не надо новую писать, и b все-таки не в пустую присваивается значение, но это gnu99, не C99.

А в C11 уже добавили полноценную стандартную проверку типов.

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

но вообще, такую вещь удобнее и логичнее оформить как ф-цию, тогда проверки пройдут автоматически, но тогда мы вернемся к первому моему утверждению - «не стоит так писать»

IvanRia
()

на мой взгляд для C++ действует это правило:
https://eel.is/c draft/expr.cond#5

для C насколько я могу судить должно быть тоже самое (очень невнятно там это изложено, как думается):
https://cstd.eisie.net/c23.html#6.5.16

хотя нет — поулчается всё так и есть — оно rvalue там:
«the result is the value of the second or third operand (whichever is evaluated), converted to the type described subsequently in this subclause.110)
110)A conditional expression does not yield an lvalue.»

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

Зато локалевые костыли в printf всё равно жрут боольшую часть производительности.
Но локали в форматере не нужны, ими всё же должны заниматься специализированные библиотеки

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

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

что тут подразумевается под «форматером»? можно ли тут формализовать «нужновость» локали, а так же определить критериальностности отнесения к таковому? что значит «специализированные библиотеки», можно ли это формализовать, а так же определить критериальностности отнесения к таковому? чем std::locale не является достаточно специализированной?

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

что тут подразумевается под «форматером»?

Что-то что форматирует строки по шаблону. Т.к эти функции используются для технических строк, а не полноценного юзеринтерфейса, поддержка локалей здесь будет излишним усложнением. Например, если в текстовом конфиге внезапно вместо точки вылезет запятая для floating point, он станет непереносимым между локалями

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

Довольно сложный вопрос. Я, например, не вижу смысла в существовании codepage-локалей в современности, когда везде есть utf-8/utf-32, а стандартная библиотека (во всяком случае Си) хоть и поддерживает локализацию, но скорее наиболее неожиданными для программиста путями.
Но в случаях, когда локализация нужна, обычно локализируют и строки. В таким случае нам нужен gettext для локализации сообщений, ui тулкиты со встроенной локализацией, если мы работаем с gui/tui, unicode-утилиты для получения количества печатных символов, а не сырых кодпоинтов/байтов, если поставлена такая задача (что само по себе спорный вопрос т.к может не быть чёткого разделения для некоторых символов). А sprintf, который будет форматировать логи и технический вывод этим всем нагружать просто бессмысленно

std::locale

Пока что эта штука принесла мне кучу проблем вроде выкидывания исключений в неожиданных местах, поломок старых libc, ошибок сборки, но не помню ни одного случая, чтобы она была полезна

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

поддержка локалей здесь будет излишним усложнением

А sprintf, который будет форматировать логи и технический вывод этим всем нагружать просто бессмысленно

тоесть иными словами это лишь твоё субъективное мнение, а не «ненужная»?

Т.к эти функции используются для технических строк

это как? что такое «технические строки»

Пока что эта штука принесла мне кучу проблем вроде выкидывания исключений в неожиданных местах

можно пример «неожиданных мест»? (просто я думаю ты почемуто оцениваешь вполне ожидаемые места для выброса исключений «неожиданными)

поломок старых libc, ошибок сборки

это как? как локаль могла „сломать“ libc?

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

думается необходимо формализовать «сложностность», а так же определить критериальностности отнесения к таковому

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

тоесть иными словами это лишь твоё субъективное мнение, а не «ненужная»?

обычно теримн «ненужно» в контексте ЛОРа являлся субъективным. Воспринимай, как удобнее

это как? что такое «технические строки»

Я же привёл примеры вроде логов или конфигов. Нужно точное определение?

можно пример «неожиданных мест»?

Ну например какие-нибудь ранние конструкторы приложения, с языками явно не работающего, но косвенно локали инициализирующего

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

ранние конструкторы приложения

а это что еще за сущность? :)

но косвенно локали инициализирующего

что подразумевается под «косвенно» ?

и почему эти места кажутся тебе «неожиданными» ?

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

это как? что такое «технические строки»

Очевидно: те, которые не показываются юзеру в процессе штатной работы.

можно пример «неожиданных мест»?

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

что подразумевается под «косвенно» ?

и почему эти места кажутся тебе «неожиданными» ?

Ну, например, gtk внезапно решил поменять локаль. А из-за этого основной ввод-вывод ломается.

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

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

а зачем тебе про это заботиться? ведь стандартные нормальные функции парсинга значений учитывают локаль... и там всегда правильно будет интерпретирован разделитель целой и дробных частей. — разве нет?

Ну, например, gtk внезапно решил поменять локаль. А из-за этого основной ввод-вывод ломается.

а разве ты не можешь сам в своей программе локаль установить?

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

ведь стандартные нормальные функции парсинга значений учитывают локаль

Дак у файла с конфигом, с которого ветка началась, локаль внутри не определена. Как определить, какую локаль выставлять, чтобы файл корректно распарсить? И, допустим, команда bc игнорит локаль, всегда хочет десятичную точку. С локалью всё хоршо, пока одна программа сама с собой или человеком взаимодействет...

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

С локалью всё хоршо, пока одна программа сама с собой или человеком взаимодействет...

думается, что как раз наоборот — в пределах одной программы программист сам знает что и как — ему тут не нужно ничено выяснять. А вот в случае, когда взаимодействуешь со «внешним миром» «за пределами программы» — вот тут уже нужны сторонние соглашения — в том числе локаль к таковым и относится.

И, допустим, команда bc игнорит локаль, всегда хочет десятичную точку.

получается тебе нужна локаль, которую хочет bc... тут ничего не поменялось в плане нормальности локали.

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

локаль не может быть «неопределённой» — она явно определена в каждом случае, иное дело, что ты можешь по какой либо причине не иметь сведений о таковом, однако это к теме обсуждения не относится как я считаю.

П.С. тут нет никаких «неожиданных мест» снова же — все места очевидные.

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

а зачем тебе про это заботиться? ведь стандартные нормальные функции парсинга значений учитывают локаль… и там всегда правильно будет интерпретирован разделитель целой и дробных частей. — разве нет?

Если бы «нет», разве стал бы я об этом упоминать? С gtk я знакомился давно, поэтому могу напутать. Кажется, проблема была не с вводом, а с выводом. Десятичный разделитель без спросу сменился с точки на запятую.

а разве ты не можешь сам в своей программе локаль установить?

Примерно так и решилось. Но вопрос-то был не в непреодолимости проблемы, а в «косвенно и неожиданно».

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

Примерно так и решилось. Но вопрос-то был не в непреодолимости проблемы, а в «косвенно и неожиданно».

так наоборот ожидаемо и прямо. просто ты получается неверно пытался сделать программу, поскольку предполагал ошибочно, что должно и так всё работать, но в стандарте явно сказано иное — что гарантированность правильности это задача программиста в таковом аспекте (поскольку стандарт явно декларирует, что взаимодействие с «внешним миром» «за пределами программы» выходит за его рамки и он предоставляет лишь способ настройки).

safocl ★★
()
Последнее исправление: safocl (всего исправлений: 2)
  • Markdown
Пустая строка (два раза Enter) начинает новый абзац. Знак '>' в начале абзаца выделяет абзац курсивом цитирования.
Внимание: прочитайте описание разметки Markdown.
Используйте Ctrl-Enter для размещения комментария