LINUX.ORG.RU

По Сям нубский вопрос (правильный способ определить uint32_t)

 


0

1

Бывает просыпаюсь утром и испытываю непреодолимое желание использовать в своем коде uint8_t вместо unsigned char, uint32_t вместо int и так далее.

Желание, порой, берет верх и я начинаю их использовать. Но компилятор про такие типы сам собой не в курсе. Приходится вначале каждого файла городить что-то типа

#ifndef __uint32_t_defined
typedef unsigned int uint32_t;
#define __uint32_t_defined
#endif

ну и так для каждого типа.

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

На всякий случай, типичный (для меня) мейкфайл:

SOURCE = main.c
SOURCE += bitmap.c
SOURCE += linux_framebuffer.c
SOURCE += forming_cm3.c

TARGET = photo_to_cm3_laser

CC     = gcc

CFLAGS = -Wall -O2
LIBS   = 

.PHONY: all clean

all: 
	$(CC) $(SOURCE) $(LIBS) $(CFLAGS) -o $(TARGET)

clean:
	rm *.o $(TARGET)

★★★★★

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

Это какое-то особое отклонение писать на с89 в 2018 году. Вот что не стоит делать, так это использовать гнушные расширения, да и бсдшные впрочем тоже. Но как ты собираешься писать без них?

anonymous
()

Что-то сдаётся мне, не нужны вам эти uint32_t, если вы только сейчас этим озаботились. Они нужны только сразу, когда надо разобрать ну там IP-пакет или какой-нибудь бинарный формат, где надо только 32 бит и не больше и не меньше.

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

А где в первом посте про с89? Судя по тому что у автора нет ключей с каким-то определенным стандартом, а используется gcc, то по дефолту там будет gnu11, емнип.

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

да мне кажется у него проблема с порядком байт, просто он об этом только догадывается пока

anonymous
()

Если <stdint.h> не под рукой, а fixed-width типы очень нужны, то как вариант:

#include <limits.h>

#if ULONG_MAX == 4294967295
	typedef unsigned long uint32_t;
#elif UINT_MAX == 4294967295
	typedef unsigned int uint32_t;
#elif USHORT_MAX == 4294967295
	typedef unsigned short uint32_t;
#elif UCHAR_MAX == 4294967295
	typedef unsigned char uint32_t;
#elif 32U%CHAR_BIT == 0U
	typedef struct { unsigned char v[32U/CHAR_BITS]; } uint32_t;
#endif
Последний случай либо дропнуть, либо для каждого случая определять также функции вида uint32_add()/uint32_mul/... Хз, как ещё сделать можно

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

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

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

Они нужны только сразу, когда надо разобрать ну там IP-пакет или какой-нибудь бинарный формат, где надо только 32 бит и не больше и не меньше.

НЯП в стандарте минимальные битности у типов указаны. Например, если надо прочитать 32-битное поле, то читаешь в long, и наоборот. А фиксированные типы могут понадобиться чтобы память сэкономить в некоторых случаях.

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

Код под множество древних/маломощных платформ, как вариант. Не знаю, бывает такое на практике или нет, но если особых усилий не требует - почему бы не заморочится

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

Например, если надо прочитать 32-битное поле, то читаешь в long, и наоборот.

Чушь. fread(&long_var, sizeof(uint32_t), 1, file) на 64-битном long не будет вычищать оставшиеся 32 бита ну и тем более про порядок байт тоже ничего не говорит.

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

минимальные битности у типов указаны

Минимальный размеры, из которых можно вывести битности, ЕМНИП. Но читать поле бинарного протокола фиксированного размера типом с не точно определённым размером как минимум замарочно будет

Deleted
()

Но компилятор про такие типы сам собой не в курсе.

Это какой компилятор? stdint.h нет у тебя?8

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

А чем stdint.h не угодил?

А я про него не знал :)

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

Спасибо за ответ — то, шо трэба.

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

Что-то сдаётся мне, не нужны вам эти uint32_t, если вы только сейчас этим озаботились.

эээ... а по-твоему я должен был эти знания с молоком матери впитать? В K&R про это нету, а я довольно давно на коленке пишу под avr-gcc там только uint8_t, стал разбираться что за зверь, идея понравилась, тем более, у меня уже бывали проблемы из-за разных размеров int-а.

Они нужны только сразу, когда надо разобрать ну там IP-пакет или какой-нибудь бинарный формат, где надо только 32 бит и не больше и не меньше.

А я как раз на бинарных форматах и столкнулся. Я так понимаю, сегодня, это хороший тон — писать код сразу uint8_t вместо unsigned char?

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

да мне кажется у него проблема с порядком байт, просто он об этом только догадывается пока

эээ... это ты как определяешь?

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

Но компилятор про такие типы сам собой не в курсе.

Это какой компилятор? stdint.h нет у тебя?

gcc, я ж указал

stdint.h нет у тебя?

Есть. Но это не сам собой, это с хидером, в котором переопределено. Сам собой он про int и char в курсе

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

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

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

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

Я так понимаю, сегодня, это хороший тон — писать код сразу uint8_t вместо unsigned char?

Я вообще не понимаю, зачем могут быть нужны типы неизвестного размера и знаковости. Как можно писать код с int если про его размеры ты толком ничего предполагать даже не можешь. ИМХО в 99% случаях надо использовать типа из stdint.

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

Например на 32 битах работает с ограничениями как результат, вместо работает значительно хуже, но похоже. В 99% случаев вообще плевать, пусть компилятор сам выбирает что ему лучше для данного отдельно взятого таргета.

А ты будто начитался этого дерьма (многие пункты более чем легитимны, но не все) https://matt.sh/howto-c

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

Что-то не понять автора:

If you find yourself typing char or int or short or long or unsigned into new code, you’re doing it wrong.
...
[а про least типы ничего аналогичного, типа отличия есть]

?

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

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

Не уловил логику. Что тебе мешает ставить #ifdef-ы или if-ы или что угодно? Или ты собрался по sizeof(int) определять 32-битность? У тебя ничего не получится.

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

Проблема в том, что у значений в переменной есть определённый интервал допустимых значений. Если ты используешь int для значений 1..10 000, в 99% случаев ты неуместно жрёшь память, например. Если ты используешь int для значений 1 .. 100 000, в редких случаях у тебя это значение вообще не поместится и будет вплоть до уязвимости. Когда ты используешь переменную типа uint32_t, ты точно знаешь, какие значения туда можно класть.

Legioner ★★★★★
()
Ответ на: комментарий от vodz
long l = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;

(чтение поля LE32, BE32 аналогично). Говнокод с fread без комментариев.

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

неуместно

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

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

Правильно, что без комментариев, не умеете вы не говнокоды писать и смысл слушать ваши комментарии.

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

uint32_t всем хорош, кроме того что у него сломана семантика числа и операторы типа (1U > -1) делают странное. А переполнение int32_t это такое же UB как и переполнение int.

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

uint32_t всем хорош, кроме того что у него сломана семантика числа и операторы типа (1U > -1) делают странное. А переполнение int32_t это такое же UB как и переполнение int.

Не совсем понял. uint32_t это typedef для unsigned чегото, то же про int32_t. Как у него может быть сломана какая-либо семантика? Или это критика (un)signed типов в C? Ну с этим ты ничего не сделаешь, такой вот язык, ищи workaround-ы, если тебе нужно рабочее переполнение.

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

Если ты используешь int для значений 1..10 000, в 99% случаев ты неуместно жрёшь память, например. Если ты используешь int для значений 1 .. 100 000, в редких случаях у тебя это значение вообще не поместится и будет вплоть до уязвимости.

Ты ведь не знал, что стандарт гарантирует диапазон int как минимум [-(2^31); 2^31-1]?

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

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

5.2.4.2.1 Sizes of integer types <limits.h>
minimum value for an object of type int
INT_MIN -32767

И еще в другом месте написано что sizeof(short) <= sizeof(int) <= sizeof(long).

Соответственно по стандарту int это два и более байта.

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

Соответственно по стандарту int это два и более байта.

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

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

сегодня, это хороший тон — писать код сразу uint8_t вместо unsigned char?

Смотря для чего, я как-то наткнулся на забавный баг: код на C++, прошивка для ПАКов, выхлоп кода парсится скриптами, в итоге результат парсинга был не ожидаемый, а проблема оказалась в том, что в крестовом коде использовался uint8_t, и для логов выводился через iostream, а cout (или cerr, clog, не важно), считал, что это char и вместо числа выводил букву. А внешние скрипты ожидали число и всё поломалось =)

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