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)

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

Тут ub возникает при передаче недопустимых параметров в функцию

По-моему, ты так ясно и не сказал, почему они недопустимы.

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

На каком языке?

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

интерпретируй получившиеся выражения/подвыражения так, как указано в подразделах Semantics для соответствующих выражений

В разделе семантики нет правил выполения.

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

Можешь по стандарту, а не кивками на GCC, показать, что нарушает тот код? (Если нарушает)

Насколько я понимаю, стандарт данный код не нарушает.
Он нарушает правила компилятора.

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

Ну вот strict aliasing - это и есть правило, определённое имплементациями.

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

По-моему, ты так ясно и не сказал, почему они недопустимы.

Потому что без флага -fno-strict-aliasing компилятор считает, что параметры разных типов не могут указывать в одно место.

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

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

Т.е. стандарт должен описывать правила трансляции, не уточняя во что? Так вроде сейчас так и есть.

В разделе семантики нет правил выполения.

То, что там — и есть правило выполнения. Если ты распарсил кусок программы как «* cast-expression», то правило выполнения такого выражения описано в соответствующем параграфе для *. А именно, в результате выполнения этого выражения получается lvalue типа T, обозначающее объект, на который указывает cast-expression. Разумеется, до этого ты выполнил cast-expression по нужным правилам, определил его тип «pointer to T» и объект, на который оно указывает.

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

Насколько я понимаю, стандарт данный код не нарушает.

Я бы тут не согласился. Но нарушает тот код не параграф 6.5/7, как нас пытается убедить hateyoufeel.

Он нарушает правила компилятора.

Это как? Код соответствует стандарту, компилятор соответствует стандарту, но исполняет код чёрт-те-как? Или компилятор не соответствует стандарту?

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

Потому что без флага -fno-strict-aliasing компилятор считает, что параметры разных типов не могут указывать в одно место.

Какой же параграф (параграфы) в стандарте разрешают ему так считать?

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

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

Т.е. стандарт должен описывать правила трансляции, не уточняя во что? Так вроде сейчас так и есть.

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

А именно, в результате выполнения этого выражения получается lvalue типа T, обозначающее объект, на который указывает cast-expression

Это. Не. Выполнение. Это логическая связь, фантазия, размышление о вечном.

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

Это как? Код соответствует стандарту, компилятор соответствует стандарту, но исполняет код чёрт-те-как? Или компилятор не соответствует стандарту?

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

И тут примерно тоже. Стандарт не запрещает такой код. А компилятор его обрабатывает некорректно.

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

Какой же параграф (параграфы) в стандарте разрешают ему так считать?

Никакой. Он зайцем. Главное, что никакой не запрещает.

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

И тут примерно тоже. Стандарт не запрещает такой код. А компилятор его обрабатывает некорректно.

Т.е. компилятор не соответствует стандарту?

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

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

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

Это. Не. Выполнение. Это логическая связь, фантазия, размышление о вечном.

Как будто регистры или память это не фантазия, лол.

Выполнение это способ связать семантику с синтаксисом. Т.е. «синтаксические» выражения (составленные из определённых лексем) отобразить в «семантические» выражения (lvalue с данным типом обозначающее данный объект) и т.д.

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

Т.е. компилятор не соответствует стандарту?

Ну получается что да. Хотя это, наверное, зависит от трактовки стандарта. По идее ничто в стандарте делать так не запрещает, но и не разрешает. В общем трактовать стандарт это всё равно, что трактовать коран или библию. Либо на костре сожгут, либо говном камнями закидают.

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

Я бы тут не согласился. Но нарушает тот код не параграф 6.5/7, как нас пытается убедить hateyoufeel.

Так а по-твоему, что этот код нарушает?

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

Так а по-твоему, что этот код нарушает?

Я думаю так.
Если указатель на объект сконвертировать в указатель на char* то он типа будет указывать на «первый» байт в этом объекте, см. http://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7 «When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.»
Если указатель на структуру/union сконвертировать в указатель на её первый член (в смысле, типа указателя) — то в результате получим указатель, который указывает на это член, см. http://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p15
А вот если мы конвертируем какие-то более анрилейтед указатели T* в U*, то стандарт описывает только поведение в случае конвертирования обратно. http://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7: «A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned68) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.»
Если ты делаешь что-то, кроме конвертирования обратно, в частности, используешь слева от оператора ->, то поведение не определено.

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

Ну в таком случае malloc - это ub, т.к. ты конвертируешь void*, например, в структуру.

А если void* можно конвертировать в структуру, то через него можно и структуру в структуру конвертировать и получать доступ к полям.

Т.е. struct* => char* - законно. char* => void* - законно. void* => struct* - законно.

Тогда и struct* => struct* законно.

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

Ну в таком случае malloc - это ub, т.к. ты конвертируешь void*, например, в структуру.

Ну, про malloc типа явно сказано что можно присваивать, и даже использовать для доступа: «The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated».
Хотя да, malloc, effective type и прочее с этим связанное это огромная жопоболь для стандартизаторов C. Но конкретно в этом случае типа что-то гарантируется.

А если void* можно конвертировать в структуру, то через него можно и структуру в структуру конвертировать и получать доступ к полям.

Про void* сказано только, что можно конвертировать void* в любой указатель. И любой указатель в void* и обратно, после чего он будет compare equal начальному указателю.
И только. Ни про какое другое использование, кроме сравнения, строго говорят не сказано.

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

«The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated».

Здесь сказано, что малок возвращает указатель, выравнивание которого совместимо с любым объектом. void* и без этого можно конвертить к любому типу.

Про void* сказано только, что можно конвертировать void* в любой указатель. И любой указатель в void* и обратно

6.3.2.3 Pointers

1 A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

A pointer to void may be converted to or from a pointer to any object type.

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

Т.е можно сконвертить struct s1* в void*, и это будет законно, и можно сконвертить void* в struct s2*. Ну и напрямую struct s1* в struct s2* тогда тоже можно.

Ну и в стандарте ub обычно указывают явно. Про конвертацию указателей сказано, что это ub только в случае нарушения выравнивания, так что считать это ub только потому что оно не описано, или не разрешено явно, имхо неправильно.

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

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

И не сказано, что будет, если не тот же или void* получен не из allocation function.

Т.е можно сконвертить struct s1* в void*, и это будет законно, и можно сконвертить void* в struct s2*. Ну и напрямую struct s1* в struct s2* тогда тоже можно.

А я что, говорил, что нельзя? Про напрямую явно сказано, что можно, не нужно выводить это из разрешения конверсии в void*.
Сконвертировать можно. Использовать как-то, кроме как для преобразования обратно — нет.

Ну и в стандарте ub обычно указывают явно. Про конвертацию указателей сказано, что это ub только в случае нарушения выравнивания, так что считать это ub только потому что оно не описано, или не разрешено явно, имхо неправильно.

Как раз правильно. http://port70.net/~nsz/c/c11/n1570.html#4p2:

If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint or runtime- constraint is violated, the behavior is undefined. Undefined behavior is otherwise indicated in this International Standard by the words ‘‘undefined behavior’’ or by the omission of any explicit definition of behavior. There is no difference in emphasis among these three; they all describe ‘‘behavior that is undefined’’.

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

Ну да, ты прав. Использование сконвертированного получается ub. Чем больше пытаюсь разобраться с стандартом сишки/плюсов, тем больше убеждаюсь в том, что это груда костылей. Почему alloc’ам можно, а остальным нет, даже если с выравниванием всё ок?

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

Т.о. код стандарт нарушает, но проблема не в этом, а в strict aliasing’е.

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

Ну да, ты прав. Использование сконвертированного получается ub.

Ну раз разобрался, тогда скажи, почему с malloc-ом тоже разное поведение в зависимости от оптимизаций :D

#include <stdio.h>
#include <stdlib.h>

typedef struct { int i1; } s1;
typedef struct { int i2; } s2;

void f(s1 *s1p, s2 *s2p) {
	s1p->i1 = 2;
	s2p->i2 = 3;
	printf("%i\n", s1p->i1);
}

int main() {
	void* alloced = malloc(sizeof(s1) + sizeof(s2));
	f(alloced, alloced);
}

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

В стандарте плюсов в общем дела получше, чем в стандарте C. (Даже описано, когда происходит access) (Но с allocation function-s там проблем ещё больше).

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

Ну раз разобрался, тогда скажи, почему с malloc-ом тоже разное поведение в зависимости от оптимизаций :D

Потому что проблема не в том, что тут ub по стандарту, а в том, что компилятор ожидает, что s1p и s2p указывает на разные области памяти. Это заморочки компилятора, сделанные ради оптимизации.

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

// f.h
#pragma once

typedef struct { int i1; } s1;
typedef struct { int i2; } s2;

void f(s1 *s1p, s2 *s2p);

// f.c
#include <stdio.h>
#include "f.h"

void f(s1 *s1p, s2 *s2p) {
        s1p->i1 = 2;
        s2p->i2 = 3;
        printf("%i\n", s1p->i1);
}

// main.c
#include <stdlib.h>
#include "f.h"


int main() {
        void* alloced = malloc(sizeof(s1) + sizeof(s2));
        f(alloced, alloced);
}

Тут компилятор понятия не имеет, что ему передают на вход в f() и ub это или нет. А результат всё равно зависит от оптимизаций.

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

Т.е. компилятор не соответствует стандарту?

С учётом того, что доступ к полям после каста - ub, то единственное несоответствие стандарту в strict aliasing’е, это каст указателя, возвращённого malloc несколько раз к разным типам. Вполне возможно, что и на это запрет где-то можно найти.

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

По Фрейду, имел в виду b.

Я имел в виду доступ через указатели, когда у структур разное выравнивание…

6.3.2.3 7

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 68) for the referenced type, the behavior is undefined. …

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

Во-первых, очень хотел ответить, что вся проблема с оптимизацией указателей была вызвана тем, что в Си длительное время не было такого понятия, как «передача по ссылке» - как вы намерены брать указатель на значение в регистре? Передача по ссылке была в фортране, в коболе, в паскале, но K&R решили, что они выше этого. И на фоне технологий 70-х они даже в чем-то были правы, потому что оптимизирующих компиляторов не было. И здесь мы снова приходим к тому, что Си устарел уже в 80-х.

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

Давай-ка поподробнее

https://queue.acm.org/detail.cfm?id=2010365 - The Most Expensive One-byte Mistake
Did Ken, Dennis, and Brian choose wrong with NUL-terminated text strings?

Наконец-то сел и прочитал статью полностью. Я не вижу у автора статьи понимания мотивов. Хотя, даже я до конца не могу понять, почему все-таки индустрия осталась на Си.

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

byko3y ★★★★
()
Последнее исправление: byko3y (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.