LINUX.ORG.RU

В чём смысл делать так_s постфиксить_t ?

 , , ,


0

2
typedef struct name_s
{
   ....
}name_t

Сабж по постфиксам.

Я делаю всегда так

typedef struct name_t 
{
   ....
}name_t

И стараюсь не не дать так

typedef struct
{
   ....
}name_t

Ибо pahole и иже с ним не могут в анонимные. Но в чём практический смысл задавать и _s и _t одновременно просто постфиксы вносят ясность и смягчают уровень былого отвращения к typedef нивелируя тот упрёк что с typedef теряется ясность. Но вернёмся к постфиксам. Ну или префиксам для типов аля t_uint8 t_int64 вместо uint8_t int64_t может тут есть извращенцы я не знаю :D

ТайпдеТупедефаете вы как?

★★★★★

Последнее исправление: LINUX-ORG-RU (всего исправлений: 3)

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

Ты, видимо, про эпопею с export в C++ забыл

Даже не знал. Я очень поверхностно знаком с крестами и считаю его худшим из популярных языков.

Так какой именно реализацией определяются C и C++?

В крестах - бардак. По базовому функционалу GCC, MSVC, ICC, а позже и Clang, очень близки, хоть и имеют каждый свои расширения.

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

которого там на самом деле нет

Есть, ты ж обратного не доказал

асты на C-style касты, чтобы этот код был well-formed C-кодом, то там также не будет UB

лол

похоже, ты просто не умеешь следить за темой

Я ж говорю - вынь из себя шланг

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

Есть, ты ж обратного не доказал

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

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

Алсо, как часто ты видишь сборку проектов с этим флагом?

О, вспомнил! Весь GObject/GLib/Gtk/Gnome компилируется с -fno-strict-aliasing.

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

Это ты про какой код? Про ведро? Так оно со strict aliasing работать, скорее всего, не будет

Не наверное, а точно не будет, потому что это линукс. А на "-O3" работать будет, но с редкими глюками. В GCC есть много сомнительных оптимизаций, потому и придумали все эти флаги -fno-gcse, -fno-if-conversion, и прочие. В среднем strict aliasing дает несколько процентов ускорения, но это в среднем, а в конкретном случае давать оно может и плюс, и минус, и ноль.

Стоит ли такая «оптимизация» выделки? Посмотрите еще на код В чём смысл делать так_s постфиксить_t ? (комментарий) , и обратите внимание на то, что strict aliasing не дал никакой оптимизации, а тупо сломал код.

byko3y ★★★★
()

Напоминает венгерскую нотацию.

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

В первом и втором случае доказал.

В третьем и четвёртом тоже. Т.к. судя по

https://www.linux.org.ru/forum/development/15505635?cid=15506470

Хоспаде, ну замени x.f на auto y = x.f;, делов-то

поциент признал, что для UB нужен доступ (чтение/запись), а в *reinterpret_cast<int*>(s); его нет.

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

Вот спасибо, приятное конструктивное доступное чтиво.

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

Ну вот, о чём я и говорил - ты не можешь доказать своё утверждение

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

в конкретном случае давать оно может и плюс, и минус, и ноль

Может и не дать. Означает ли это ненужность такого рода оптимизаций?

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

Вопрос на засыпку свидетелю секты strict aliasing rule.

struct S { int i; } s;
struct T { int i; } t;

int* pi = &((T*)&s)->i;

Есть ли тут UB? Если есть, то почему?

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

в конкретном случае давать оно может и плюс, и минус, и ноль

Может и не дать. Означает ли это ненужность такого рода оптимизаций?

Значит, на фоне того, что strict aliasing по умолчанию ломает код. Особенно если учесть, что strict aliasing запрещает взятие указателя на поле структуры, в том числе на поле-подструктуру, что делает любая программа на Си, которая по сложности значительно выше hello world. Также я бы посоветовал подумать нед тем, что со strict aliasing нельзя собрать как минимум stdlib.

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

C11, 6.5. Expression.
«An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of theo bject,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.
foo f;
foobar( &f, &f.x );
— a character type.»

А также, 6.3.2.3 Pointers.
«A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined.»

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

со strict aliasing нельзя собрать как минимум stdlib

Не вспоминается примеров(ну окромя offsetof и пр., но это не по теме алиасинга)

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

со strict aliasing нельзя собрать как минимум stdlib

Не вспоминается примеров(ну окромя offsetof и пр., но это не по теме алиасинга)

memcpy

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

Там как раз алиасинг невозможен. Или ты про приведение к void*?

Chunk optimization недопустим при strict aliasing, а memcpy использует именно его.

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

Вопрос на засыпку свидетелю секты strict aliasing rule.
struct S { int i; } s;
struct T { int i; } t;
int* pi = &((T*)&s)->i;
Есть ли тут UB? Если есть, то почему?

Да, есть, в GCC, потому что они поехавшие сектанты. Ничего нового, собственно. Это даже по стандарту не должно было быть UB.

#include <stdio.h>
 
typedef struct { int i; } S;
typedef struct { int i; } T;
 
void f(S *s, T *t) {
  s->i = 1;
  t->i = 2;
  printf("%i\n", s->i);
}
 
int main() {
  S s = {.i = 0};
  f(&s, (T *)&s);
}
$ gcc cerberus.c && ./a.out
2
$ gcc -O2 cerberus.c && ./a.out
1
$ gcc -O2 -fno-strict-aliasing cerberus.c && ./a.out
2
byko3y ★★★★
()
Ответ на: комментарий от DllMain

Кстати, тезис насчёт неоднозначностей в стандартах c и c++ принимаешь? Этот тред вполне себе подтверждение

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

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

Операция взятия подстроки с копированием и сменой ownership не мутирует исходную строку.

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

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

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

У Си был изначальный посыл «мы изолируемся от механизма выделения памяти». То есть, память может выделяться в стэке, статично, или динамически. Такая модель была актуальна для 70-х годов, но начала устаревать уже в 80-х, когда размер памяти начал превышать 64 КБ, отдельные строки перестали влазить в стэк, а выделять большое число буферов под многочисленные строки во всё более усложняющихся программах стало недопустимым расточительством.

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

Как теперь на эту модель натянуть механизмы возврата строк, или хотя бы защиту от выхода за границы буфера? Java, C++, Python вполне себе используют взятие подстроки ссылкой на исходную строку - это позволяет делать быстрые парсеры, и вообще, хороший прием для устранения лишнего фрагментирования памяти. Таким образом, в Си нужны механизмы передачи длины строки и длины буфера, а еще желательно добавить счетчик ссылок для многопоточного доступа. В Plan 9 это реализовали как-то вот так:
http://man.cat-v.org/plan_9/2/string

typedef struct String {
	Lock;
	char	*base;	/* base of String */
	char	*end;	/* end of allocated space+1 */
	char	*ptr;	/* ptr into String */
	short	ref;
	uchar	fixed;
} String;

А нуль-терминированности в любых раскладах место на свалке.

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

An object shall have its stored value accessed only by an lvalue expression that has one of the following types: — a type compatible with the effective type of the object

ph->p; это lvalue с типом void* и тип объекта на который это lvalue обозначает имеет тип void*. Так что это по этому правилу всё ОК.

А также, 6.3.2.3 Pointers.

Считай, что с выравниванием всё в порядке.

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

Я вопрос задал про один код, а ты постишь ответ про другой код.

Ещё раз, есть ли UB в следующем коде и почему:

struct S { int i; } s;
struct T { int i; } t;

int* pi = &((T*)&s)->i; // есть ли тут UB?
anonymous
()

Вопрос от неосилившего разобраться со strict aliasing к господам срущимся. В файлике <sys/epoll.h>, в структуре epoll_data есть поле void* ptr. Специально предназначенное для хранения указателя на пользовательские данные. Как мне его приводить к указателю на мой тип? Щас я делаю reinterpret_cast<MyType*>(data.ptr). Назад в общем-то и так присваивается.

dimgel ★★★★★
()

Да пишут на сях и крестах кто во что горазд. Это в JavaScript есть всякие Airbnb style линтеры и «code style», а в C только если в одно рыло чел пишет, тогда и будет единый «code style»

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

Легко валятся всякие самоуверенные недоучки, думающие, что тип выражения E1 в выражениях вида E1.E2 имеет какое-то значение для strict aliasing rule.


Вау! Как же так? Анонимус же сказал, что тип структуры значения не имеет!

Твои способности делать выводы из эксперимента как в следующем анекдоте.

Встречаются как то Петька с Чапаевым, говорит Петька:

— Товарищ Чапаев, дайте 5 рублей на опыты!

Чапаев достает и отдает деньги. Через 3 дня проходит около сарая и видит, заходя в сарай, что лежит Петька пьяный в стельку, а рядом лежит блокнот. Берет и читает:

— Опыт 1-й: берем таракана, отрываем ему 2-е ноги, свистим таракан убегает!

Опыт 2-й: берем отрываем таракану еще 2-е ноги, свистим таракан убегает!

Опыт 2-й: берем отрываем таракану последние ноги, свистим таракан стоит!

Вывод: таракан без ног не слышит!

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

ph->p; это lvalue с типом void* и тип объекта на который это lvalue обозначает имеет тип void*. Так что это по этому правилу всё ОК

Указатель ph нарушает правило, а с указателем ph->p всё в порядке, не про него разговор.

А также, 6.3.2.3 Pointers.

Считай, что с выравниванием всё в порядке

Описание операций с указателями не предполагает разыменовывания этих указателей. Разыменовывание описывается в 6.5. Expressions.

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

struct S { int i; } s;
struct T { int i; } t;
int* pi = &((T*)&s)->i; // есть ли тут UB?

Если кроме этого кода в программе ничего нет, то UB нет. Можно спорить, пытаться интерпретировать стандарты, но с практической точки зрения программа настолько ничего не делает, что нет смысла оценивать поведение, которого нет.

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

Если кроме этого кода в программе ничего нет, то UB нет.

Ок. А использовать pi для чтения/записи можно?

struct S { int i; } s;
struct T { int i; } t;
int* pi = &((T*)&s)->i;
int i = *pi; // есть ли тут UB?
anonymous
()
Ответ на: комментарий от anonymous

Указатель ph нарушает правило

Каким образом? Раскрой мысль.

К сожалению, стандарт написан ублюдочным языком, потому его не всегда просто понять:
3.15
«object — region of data storage in the execution environment, the contents of which can represent values»
6.5.2.3
«A postfix expression followed by the -> operator and an identifier designates a member of a structure or union object. The value is that of the named member of the object to which the first expression points, and is an lvalue. If the first expression is a pointer to a qualified type, the result has the so-qualified version of the type of the designated member.»

Я могу согласиться разве что с тем, что стандарт не указывает, нужно ли рассматривать выражение «pntr->field» аналогично "(*pntr).field", то есть, применять к промежуточному lvalue правила из 6.5 параграф 7. Двигаясь от обратного, можно выяснить, что если этого не делать, то получается лютая дичь с доступом по неограничено различным смещениям, при условии что типы полей совпадают, вроде:

struct {
  int a;
  float b;
} S;
struct {
  float c;
  char d;
} T;

int main () {
  S s = {0, 1.0};
  printf("%f\n", ((T*)&s)->c);
}
byko3y ★★★★
()
Ответ на: комментарий от menangen

Да пишут на сях и крестах кто во что горазд. Это в JavaScript есть всякие Airbnb style линтеры и «code style», а в C только если в одно рыло чел пишет, тогда и будет единый «code style»

В Си тоже есть стили. Просто их несколько, поскольку язык довольно слабо ограничивает программиста во вспомогательных символах. Это просто в JS если перенес фигурную скобку на другую строчку - всё, расстрел, отдельные браузеры не смогут распознать код.

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

Тебе религия запрещает сделать свой строковый тип с помощью структуры и typedef?

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

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

struct S { int i; } s;
struct T { int i; } t;
int* pi = &((T*)&s)->i;
int i = *pi; // есть ли тут UB?

В 6.5 параграф 6 описывается применение типов к объектам. В твоем коде «s» становится объектом с типом «struct T» и доступ к нему далее возможен только как к «struct T». Ну, или как к бестиповому значению, или как к struct/union, содержащему «struct T».

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

Я могу согласиться разве что с тем, что стандарт не указывает, нужно ли рассматривать выражение «pntr->field» аналогично «(*pntr).field», то есть, применять к промежуточному lvalue правила из 6.5 параграф 7.

Даже если бы он говорил рассматривать E1->name как (*(E1)).name, то это не было бы причиной считать что в выражениях вида EL = ER, где EL или ER имеют вид E1.name, strict aliasing rule интересуется не только типом EL/ER при записи/чтении через эти lvalue, но и типом E1.

Двигаясь от обратного, можно выяснить, что если этого не делать, то получается лютая дичь с доступом по неограничено различным смещениям, при условии что типы полей совпадают, вроде

Для того, чтобы считать лютую дичь лютой дичью, не обязательно применять strict aliasing rule как левой пятке захотелось. Есть другие способы. Но, естественно, стандарт придётся «слегка» дописать. Точнее, сильно переписать.

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

В 6.5 параграф 6 описывается применение типов к объектам. В твоем коде «s» становится объектом с типом «struct T» и доступ к нему далее возможен только как к «struct T».

Ты про effective type? effective type не меняется из-за кастов указателей. Для объектов с declared type, effective type вообще нельзя поменять.

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

Ты про effective type? effective type не меняется из-за кастов указателей. Для объектов с declared type, effective type вообще нельзя поменять

Ну явно они не запрещают, правда, и не разрешают. Да. написанный тобой код по стандарту корректен, эффективный тип s будет struct S, а доступ как к struct T допустим, поскольку тип совместим. Что не отменяет того факта, что GCC со strict aliasing умудряется ломать код при использовании совместимых типов.

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

Даже если бы он говорил рассматривать E1->name как (*(E1)).name, то это не было бы причиной считать что в выражениях вида EL = ER, где EL или ER имеют вид E1.name, strict aliasing rule интересуется не только типом EL/ER при записи/чтении через эти lvalue, но и типом E1

Каким образом стандарт не распространяется на подвыражения? «*(E1)» является выражением языка Си? Является. Чтение/запись, как то арифметические операции, инкремент, простое чтение или запись значения являются использованием объекта в выражениях, потому должны подчиняться 6.5 параграф 7.

Для того, чтобы считать лютую дичь лютой дичью, не обязательно применять strict aliasing rule как левой пятке захотелось. Есть другие способы. Но, естественно, стандарт придётся «слегка» дописать. Точнее, сильно переписать

Чтол переписываать? Зачем переписывать? Мой пример показывал, что неприменение правила совместимости типов структур при доступе к их членам приводит к бессмысленному коду. Таким образом это допущение очевидно бессмысленно, пусть и не упомянуто явно в стандарте.

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

6.2.7 Compatible type and composite type
«two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: If one is declared with a tag, theother shall be declared with the same tag. If both are completed anywhere within their respective translation units, then the following additional requirements apply: there shall be a one-to-one correspondence between their members such that each pair of corresponding members are declared with compatible types; if one member of the pair is declared with an alignment specifier, the other is declared with an equivalent alignment specifier; and if one member of the pair is declared with a name, the other is declared with the same name. For two structures, corresponding members shall be declared in the same order.

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

Каким образом стандарт не распространяется на подвыражения?

Ещё раз. Не рассматриваются подвыражения, когда мы рассматриваем чтение/запись через всё выражение.

Т.е. когда в EL = ER мы интересуемся, например, чтением через ER, то с т.з. strict aliasing rule важен только тип ER и тип объекта, который оно обозначает. Даже если ER имеет вид (*(E1)).name.

Естественно, к самому по себе *(E1) или E1 strict aliasing rule применим в том смысле, что при анализе выражения E1 и его подвыражений мы сопоставляем типы встречающихся там lvalue с типами объектов, которые они обозначают, при доступе к этим объектам.

Чтол переписываать? Зачем переписывать?

Стандарт. Чтобы было норм.

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

Поэтому и надо переписать, чтобы правила были явно упомянуты и всякие недоучки не думали, что при доступе через выражения E вида E1.name, strict aliasing rule рассматривает не только тип E, но и тип E1.

Не факт, что это будет правило про совместимость типов.

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