LINUX.ORG.RU

char это и не signed и не unsigned а непонятно что

 


3

6
> cat main.cpp
#include <type_traits>

int main() {
        static_assert((::std::is_same<char, signed char>::value) == true);
        static_assert((::std::is_same<char, unsigned char>::value) == true);

        return 0;
}

> g++ -Wall -Wextra main.cpp
main.cpp: In function 'int main()':
main.cpp:4:2: error: static assertion failed
  static_assert((::std::is_same<char, signed char>::value) == true);
  ^~~~~~~~~~~~~
main.cpp:5:2: error: static assertion failed
  static_assert((::std::is_same<char, unsigned char>::value) == true);
  ^~~~~~~~~~~~~
★★★★

Ответ на: комментарий от Iron_Bug

какую стройную систему? я видела архитектуры, где char 32 бита, потому что там так устроена работа с шиной и меньше 32 битов адресации нет.

Всё равно где-то придётся остановиться. Сейчас вот полно векторных архитектур, значит ли это, что в C/C++ надо поменять тип инт на «1 или несколько целых чисел»? А если вспомнить про тернарные архитектуры, значит ли что битовые операции надо выкинуть или сделать бит неопределённым? Может и float выкинуть? И даже целочисленное умножение?

Писать программу под неопределённую архитектуру невозможно.

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

понимаешь, это не вопрос «удобства». это вопрос стандарта

Кому это не вопрос удобства? Тебе? - ну пусть будет так. Мне это и вопрос удобства в том числе.

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

Я тебе так скажу: чем шире охват платформ, для которых мы хотим сделать язык с поддержкой функционала, который доступен на каждой из них - тем меньше будет этот функционал (чем больше мы будем обобщать - тем меньше получим общих признаков). Поэтому я не не за то, чтобы охватить все платформы - я за то, чтобы охватить наиболее распространенные, а вот в таких потоки есть.

вот были в бусте эти потоки и пусть бы там оставались. кто хочет «удобства», взял бы оттуда. а в стандарт такое тащить нельзя. но и «удобства» тут никакого, тащемта

Удобство в том, что не нужно тащить буст. Да, его взять легко, но когда его брать не нужно - это еще легче.

обычно проекты пишут под конкретную ОС

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

Вот работал я некоторое время с VxWorks 6.8. Там вроде бы компилятор C++98. Однако std::clock не работал не фига (т.е. всегда возвращала 0, о чем отдельно указано в документации по данной версии VxWorks). Для получения аналогичной функциональности нужно было использовать их функцию из их заголовочного файла vxWorksCommon.h. Т.е. когда нужно, вполне забивают на стандарт и делают компилятор приближенный к стандарту, но не полностью соответствующий ему.

проблему кроссплатформенности оно не решает, но рушит переносимость комиляторов и библиотек

Опять таки, исходя из того, что под специфичные платформы бывают и компиляторы кастомные, то нужна ли тебе 100%-ая переностимость? По мне так, достаточно переностимости между самыми распространенными платформами.

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

банально тем, что не на всех ОС они есть.

Не все cpu умеют умножать и делить. Стоит ли избавляться от таких операторов в языке?

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

Не думаю. Я имел в виду, что int как «какое-то целое» бессмысленнен, даже если это удобно для железа. Будет или колхоз с тайпдефами, или просто надежда на то что влезет. Поэтому дизайн языка под фиксированный размер типов лучше. Пусть лучше компилятор трудится для борьбы с невыровненным доступом к памяти, а под конкретное железо предлагаются свои нестандартные типы чем старый сишный зоопарк

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

Ссылку на стандарт? Может еще ключи от квартиры где деньги лежат? :)

6.2.5 Types

The three types char, signed char, and unsigned char are collectively called the character types. The implementation shall define char to have the same range, representation, and behavior as either signed char or unsigned char.(45)

(45) CHAR_MIN, defined in <limits.h>, will have one of the values 0 or SCHAR_MIN, and this can be used to distinguish the two options. Irrespective of the choice made, char is a separate type from the other two and is not compatible with either.
untitl3d
()
Ответ на: комментарий от andreyu

Писал для мк? Там обычно нет float. А в самом дешмане нету умножения для int (attiny13a например)

Давно уже привык жить без float. Сейчас изобретаю шаблонный fixed point чтобы вручную сдвиги не считать.

Ещё хочу попробовать уйти с фиксированных типов для хранения на least как тут писал char это и не signed и не unsigned а непонятно что (комментарий). А все вычисления внутренние давно уже на автомате делаю в fast

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

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

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

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

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

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

То-то и оно. И раз уж мы выяснили, что проекты как правило пишутся под конкретные системы. То фактически каждый раз программист выбирает тип на основе того, сколько бит ему нужно. Он знает, сколько в данном случае бит скажем у int или char. На системе, где данные типы имеют другую битность (в смысле количество бит в типе) будет выбран при прочих равных уже другой тип. Т.е. я к тому, что даже сейчас, даже использую типы char/int/long и т.п. мы все равно выбираем типы на основе битности, просто в каждом случае мы смотрим, сколько бит у типа в целевой системе/компиляторе. Так и что плохого в том, чтобы у типов было жестко указано количество бит? Что в целом и сделали в C++ сделав надстройку над фундаментальными типами в виде int8_t, int16_t и т.п.

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

Нет если не считать SHORTCHAR, CHAR. Типы по модулю переполняются (переполненные старшие биты отбрасываются).

Значения можно конвертировать в беззнаковые через формулу вида: x MOD ASH(1, 32). Наоборот в знаковое: (x + ASH(1, 31)) MOD ASH(1, 32) - ASH(1, 31).

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

для хипстеров сделаны всякие песочницы с искусственным управлением памятью и всякими там мусоросборщиками.

И это тоже. Но мы не про такие языки.

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

Как раз ровно наоборот.

Если ты пишешь for(int32_t i = 0; i < 100; i++){... i*1000...} тогда ты знаешь сколько у тебя бит, какие значения может принимать i и то что его можно безопасно умножать на 1000. Если ты пишешь int то ты именно что надеешься на то что его хватит для представления 99000. Потом твой код может оказаться на другом компиляторе под другую архитектуру, его могут тупо копипастнуть в чужой проект, просмотрев снаружи и не заметив криминала. Т.е. даже под определение «переносимый ассемблер» в данном случае C не очень-то подходит. Если уж так заботиться об удобстве компилятора, надо было вводить типы типа int_at_least32_t, с UB в случае переполнения 32 бит.

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

код не может «оказаться» где-то просто так. это не случайная фигня, которой занимаются ламеры.

если ты хочешь переносить код на другую платформу - надо его весь просматривать на предмет подобных вещей. если ты хочешь писать код под кроссплатформу - это вообще отдельная тема, для этого есть typedef и define и там организуют типы под разные платформы, и платформозависимый код выносят в отдельные файлы, которые собираются в зависимости от архитектуры. это всё делается осознанно.

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

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

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

это может оказаться несовместимо с архитектурой и потому бессмысленно.

А почему это МОЖЕТ оказаться? Мы ведь уже пришли к соглашению, что проекты пишут под определенные платформы, а значит заранее знают, что доступно, а что нет. Не должно быть никаких МОЖЕТ, если не идет копипаста чужого кода в изначально не планированную платформу.

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

А почему это МОЖЕТ оказаться? Мы ведь уже пришли к соглашению, что проекты пишут под определенные платформы

Я больше скажу - под конкретные семейства чипов (Intel vs AMD), и под конкретные компиляторы / системное окружение. Можно, конечно, создавать условного сферического коня в вакууме который «работает всегда и везде», но цена (особенно в плане TTM) будет зашкаливать. А так: unit тесты прошли (спешу заострить внимание на том что всё покрыть невозможно) - есть определенная уверенность (надежда?) что ничего не взорвётся, и можно выкатывать. А вот когда возникнет необходимость спортироваться куда то ещё - тогда и будем думать «как» и «чего это будет стоить». Мои 2 копейки.

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

Many programs require byte-oriented access to memory. Today, such programs must use either the char,signed char, or unsigned char types for this purpose. However, these types perform a “triple duty”. Not only are they used for byte addressing, but also as arithmetic types, and as character types. This multiplicity of roles opens the door for programmer error – such as accidentally performing arithmetic on memory that should be treated as a byte value – and confusion for both programmers and tools. Having a distinct byte type improves type-safety, by distinguishing byte-oriented access to memory from accessing memory as a character or integral value. It improves readability. Having the type would also make the intent of code clearer to readers (as well as tooling for understanding and transforming programs). It increases type-safety by removing ambiguities in expression of programmer’s intent,thereby increasing the accuracy of analysis tools. The key motivation here is to make byte a distinct type – to improve program safety by leveraging the type system. This leads to the design that std::byte is not an integer type, nor a character type. It is a distinct type for accessing the bits that ultimately make up object storage.

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

Какой ещё бит? По той же логике не для каждого байта конкретный бит что-то значит. Например, внутри байта есть 3 битовое поле, отдельные биты внутри этого поля ничего не значат

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

Мне кажется тебе просто чужда сама концепция типов. Ты пришёл из ассемблера или из питона и просто это всё для тебя в диковинку. Почитай что-то самое базовое про Си++. Там тебе расскажут про базовые типы. И про созданные пользователем типы и нахрена они нужны.

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

Мне чужда концепция бесполезных типов. Типа void*. Смысла ноль, у любого значения этого типа судьба быть приведённым к какому-то другому указателю

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

Ты читал про наследование? Базовые типы являются базисом для пользовательских реально полезных типов. При этом сами по себе они не обязаны быть полезными. Иногда они даже в принципе не могут стать объектом в памяти.

В общем, отстань от плюсов. Это свой мир о котором ты не имеешь ни малейшего представления и лезешь сюда с сишным уставом.

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

Писал для мк? Там обычно нет float. А в самом дешмане нету умножения для int (attiny13a например)

И что, избавляемся от float, деления, умножения в языке?

Сейчас изобретаю шаблонный fixed point чтобы вручную сдвиги не считать.

Зачем изобретать, давно уже изобретено и проверено временем.

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

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

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

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

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

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

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

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

Во первых, я обсуждаю плюсы. Во вторых ты путаешься в последовательности обсуждения.

Есть фундаментальные типы определенные в стандарте так: минимум столько-то бит и не более чем тип такой то.

При этом мы согласились (ты тоже) что проекты пишут каждый раз под определенные архитектуры и для каждой конкретной архитектуры для фундаментальных типов в реализации будет уже конкретное число бит.

Поэтому даже сейчас при выборе типа учитывается его битность на целевой платформе.

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

А ты как настоящий демагог уводишь в сторону и пишешь вообще не про то, что тут обсуждается.

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

Хорошо. Но мне бы хотелось неявный каст к bool, чтобы немного проще делать проверку. Или какую нибудь отдельную функцию для явной провеки бита. Типа как в std::bitset<N>::test().

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

При этом мы согласились (ты тоже) что проекты пишут каждый раз под определенные архитектуры и для каждой конкретной архитектуры для фундаментальных типов в реализации будет уже конкретное число бит.

Прошу прощения, что ставлю под сомнение идиллию вашего консенсуса, но может объясните мне, а как проекты типа:

  • библиотек, вроде Qt или ffmpeg?

  • СУБД, вроде MySQL, SQLite, BerkeleyDB и пр.?

  • десктоп-приложения, которые развиваются в течении 30-35 лет, зародившись на 16-битовых 8086, а сейчас работающие на 64-битных x86 и ARM-ах?

Они что, каждый раз пишутся под определенные архитектуры?

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

Они что, каждый раз пишутся под определенные архитектуры?

Думаю да. Вот на примере Qt: https://doc.qt.io/qt-5/supported-platforms.html

Каждый проект, лучше даже сказать конкретная версия проекта, разве не идет под что-то определенное (не обязательно под одну платформу, но под некоторое количество платформ, вон как Qt)? И даже почитав описание сборки на том же CMake можно увидеть условия для конкретных платформ.

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

Я понимаю как его используют, но это не отменяет того факта что с ним ничего нельзя сделать кроме как скопировать и кастануть в другой тип. Т.е. сам по себе он бесполезен

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

Нет.

Просматривать код на предмет подобных вещей - это бред, это необходимость, вызванная ошибкой дизайна «кросплатформенного ассемблера». Прочитать чужой на 100 раз проверенный код, понять его, допереть до возможных подводных камней, потом проверить его корректность на текущей платформе - может лучше уж тогда просто с нуля переписать?

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

khrundel ★★★★
()