LINUX.ORG.RU

типы в c

 ,


1

3

есть такая структурка:

struct x { int i; ... char buf[4096 - ???]; };

проблема в размере buf. должно быть так:

static_assert(sizeof(struct x) == 4096);

как написать там нужный размер без боли? очевидный вариант не проходит:

struct x { int i; ... char buf[4096 - offsetof(struct x, buf)]; }; // struct x is incomplete
struct x { struct { int i; ... } y; char buf[4096 - sizeof(y)]; }; // y is undeclared
struct x { struct y { int i; ... } y; char buf[4096 - sizeof(struct y)]; }; //это работает, но как и в предыдущем случае нужно будет писать x.y.i вместо x.i

лучшее, что придумал:

struct x { union { struct { int i; ... char buf[]; }; char _[4096]; }; };

но хочется иметь простой sizeof(buf), а не костылями. есть ли способ?



Последнее исправление: jsforever (всего исправлений: 2)

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

массивы имеют длину и хранят её где то

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

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

sizeof(p) даст мне просто размер указателя

раз уж p указатель, то размер указателя и даст sizeof(p).

Если бы хотелось, чтобы p был указателем на массив из 10 элементов int, то:

int (*p)[10];

sizeof(p) == размер указателя,
sizeof(*p) == sizeof(int)*10 (тоже случай сохранения размера массива времени компиляции).

bormant ★★★★★
()
struct x { union { struct { int i; ... char buf[]; }; char _[4096]; }; };

Дичайший говнокод. Если это какая-то мессага, которая которую надо сериализовать, выкидываем нахрен эту структуру, и просто работаем с char buf[4096], вставляя куда надо данные.

seiken ★★★★★
()

На плюсах я в таких случаях подгоняю размер buf вручную, а под структурой пишу: static_assert(sizeof(x) == 4096);

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

это лучшее решение без макросни. а так, ты должен выкинуть структуры вообще с заменой на char[] - ведь от того, надо ли это сериализовать или нет, не зависит ничего.

зачем ты сюда пришёл, эникей? иди в толксы. для этого раздела ты слишком некомпетентен.

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

эникей

У тебя все через одного либо гуманитарии, либо эникеи. Да что с тобой не так, дружище? Тут форум. Каждый может предложить свои идеи и своё виденье относительно обсуждаемого вопроса. Почему ты на всех кидаешься с оскорблениями?

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

В нормальных языках типа раста хранят

Лол. Поделил на ноль))

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

ведь от того, надо ли это сериализовать или нет, не зависит ничего.

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

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

типы в c (комментарий). практически идеальное решение.

Это ж вообще не решение. Компилятор пошлет лесом уже на слове «template».

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

Похоже это была реинкарнация Царя, но какая то унылая, харизмы не хватало… но мы его не ценили и таки потеряли:-(

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

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

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

Ники он менял регулярно поскольку его регулярно банили. Подход к общению у него был как у ТС только поярче - «Я царь сишки а ты жалкая/анскильная лалка»!

По «анскильной лалке» можно поискать:-)

Ну и такой фигнёй как ТС он бы не стал страдать, квалификация у него была явно повыше.

Так что ТС на Царя не тянет, так - анскильный царенок максимум:-(

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

Так что ТС на Царя не тянет, так - анскильный царенок максимум:-(

Судя по описанию, он не стал бы использовать ник js forever xD

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

Царь просто подстраивается под модерацию — таков плачевный результат бесконечного закручивания гаек. Вот уже и шлюхой с порога не называет, только через N постов либо в телеграме.

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

Нигде не хранят, длина массива задаёт его типом.

В нормальных языках типа раста хранят

Нет конечно, в расте массивы имеют константный размер времени компиляции. Ты путаешь со слайсами и heap-allocated контейнерами типа vec.

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

Нет конечно, в расте массивы имеют константный размер

разумеется, я и не утверждал обратного

fn len_of_slice(slice: &[i32]) -> usize {
    slice.len()
}


fn main() {
    let array = [1, 2, 3, 4, 5];
    println!("The length of the array is: {}", array.len());
    println!("The length of the sliсe is: {}", len_of_slice(&array));

}

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

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

В этом смысле и в Си х ранят,

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

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

В Си есть еще такая штука, как malloc_usable_size. Только она, похоже, в стандарт не входит. По крайней мере, в gcc работает, в mingw - нет.

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

нет в этом смысле и каком-либо другом смысле не хранят

В этом смысле хранят, например, указатель на массив массивов p++ инкрементируется длиной массива.

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

В си нет механизма проверки границ массива, в расте есть. Разница в этом, а не в «хранении» размера массива.

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

В этом смысле хранят, например, указатель на массив массивов p++ инкрементируется длиной массива.

что? инкрементируется длиной массива? Это как? ЛОЛ

В си нет механизма проверки границ массива, в расте есть. Разница в этом, а не в «хранении» размера массива.

как по-вашему происходит проверка границ массива, если размер массива не «хранится»?

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

Это как?

#include <stdio.h>

int main() {
    // Define a 2D array with 3 rows and 4 columns
    int array[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    // Pointer to the entire array of 4 integers (one row)
    int (*ptr)[4] = array;

    printf("Initial pointer address: %p\n", (void*)ptr);

    // Iterate over each row using the pointer
    for (int i = 0; i < 3; i++) {
        printf("Row %d address: %p\n", i, (void*)ptr);
        printf("First element of row %d: %d\n", i, (*ptr)[0]);

        // Increment the pointer to point to the next row
        ptr++;
        printf("Pointer incremented to: %p\n\n", (void*)ptr);
    }

    return 0;
}

как по-вашему происходит проверка границ массива, если размер массива не «хранится»?

Размер массива «хранится», а не хранится. Нет области памяти или переменной с размером массива, которая будет являться частью массива. Компилятор знает размер массива из его типа, и может подставлять его в нужных местах, например, при копировании массива или проверки индекса. Этот размер есть в программе как часть кода программы, а не часть данных, которые программа обрабатывает.

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

Вообще, размер массива хранится в том же смысле, в каком в программе хранится размер int или какой-нибудь структуры. Как в расте, так и в си, никакой разницы.

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

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

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

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

В расте нельзя взять просто указатель на массив

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f44b06360634625ba4c59671e9e135a2

вы всегда будете иметь пару указатель + длина массива

fat pointers используются в случаях, когда длина типа неизвестна на этапе компиляции, например dyn типы или слайсы.

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

вы же хотели сказать размером элемента массива, да же?

Массив двумерный, элемент массива является массивом, вот длину «внутреннего» массива я и имел в виду.

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

fat pointers используются в случаях, когда длина типа неизвестна на этапе компиляции, например dyn типы или слайсы.

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

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

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

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

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

 Но по факту ситуация одинаковая… это ровно то же самое, что происходит, когда мы пишем ptr++ в сишном примере.

прошу вас, воспроизведите на Си вот такой код

fn total(a: &[&[i32]]) -> usize {
    return a.into_iter().map(|x| x.len()).sum()
}

const RANDOM: i32 = 3;

fn main() {
    let a = [1, 2, 3, 4];
    let b = [4, 5];
    let c = [5, 6];
    let d = [1, 2, 3];
    println!("{}", total(&[&a, &b, if (RANDOM % 2 == 0) {&c} else {&d}]));
}

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

Слайсы хранят свою длину, не массивы

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

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

до отсутствия в си слайсов, трейтов и проверки границ.

вот в этом и отличие. Вы же на просьбу воспроизвести мой пример на си отвечаете «В си нет слайсов. Слайсы хранят свою длину, не массивы», значит разница ломающая подход к написанию кода есть и она не дает вам возможности переписать растовый код на си. Где бы эта самая длина не хранилась, она хранится, и раст делает это сохранение прозрачно и невидимо, пусть даже там под капотом юзается sizeof. Ну вперед, пожалуйста, заюзайте силу sizeof, чтобы мой пример стал работать на си.

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

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

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

Ну и да, вот вам эквивалентный код от чатгпт, как видим никакой ломающей разницы, просто разные типы слайсов приходится определять отдельно, как и заполнять их приходится вручную:

#include <stdio.h>
#include <stddef.h>

// Define a Slice struct to hold a pointer to an array and its length
typedef struct {
    int *data;
    size_t len;
} IntSlice;

// Define a SliceSlice struct to hold an array of Slice structs and its length
typedef struct {
    IntSlice *data;
    size_t len;
} SliceSlice;

// Function to calculate the total length of all slices
size_t total(SliceSlice slice_slice) {
    size_t sum = 0;
    for (size_t i = 0; i < slice_slice.len; i++) {
        sum += slice_slice.data[i].len;
    }
    return sum;
}

// Define the RANDOM constant
const int RANDOM = 3;

int main() {
    // Initialize the arrays
    int a[] = {1, 2, 3, 4};
    int b[] = {4, 5};
    int c[] = {5, 6};
    int d[] = {1, 2, 3};

    // Create an array of Slice structs
    IntSlice slices[3];

    // Assign the first slice
    slices[0].data = a;
    slices[0].len = sizeof(a) / sizeof(a[0]);

    // Assign the second slice
    slices[1].data = b;
    slices[1].len = sizeof(b) / sizeof(b[0]);

    // Determine which slice to use based on RANDOM
    if (RANDOM % 2 == 0) {
        slices[2].data = c;
        slices[2].len = sizeof(c) / sizeof(c[0]);
    } else {
        slices[2].data = d;
        slices[2].len = sizeof(d) / sizeof(d[0]);
    }

    // Create a SliceSlice struct to hold the array of slices
    SliceSlice slice_slice;
    slice_slice.data = slices;
    slice_slice.len = 3;

    // Calculate the total length
    size_t total_length = total(slice_slice);

    // Print the result
    printf("%zu\n", total_length);

    return 0;
}
unC0Rr ★★★★★
()
Ответ на: комментарий от FishHook

разница ломающая подход к написанию кода есть и она не дает вам возможности переписать растовый код на си

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

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

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

FishHook
()
Последнее исправление: FishHook (всего исправлений: 1)
struct x { int i; ... char buf[4096 - offsetof(struct x, buf)]; }; // struct x is incomplete

У двух одинаковых структур будет одинаковое смещение.

#include <stdio.h>
#include <stddef.h>

struct dummy_crap_x {
    int i;
    char buf[4096];
};

struct x {
    int i;
    char buf[4096 - offsetof(struct dummy_crap_x, buf)];
};

int main()
{
    printf("Size of struct x: %ld\n", sizeof(struct x));
    return 0;
}

В итоге

Size of struct x: 4096

https://www.online-cpp.com/CwS8BMqvX0

А эстетикой можно подтереться, потому что это не про Си.

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

Ты дебил…

Ты чуешь чем пахнет? Снова горелым беконом))

… в тексте реперные точки …

Знаешь, если в текст пихать умные слова, то для кого-то он может показаться умнее, но это только для кого-то и только кажется. От умных слов эта глупость умнее не стала)

… что же имел в виду автор

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

PRN
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.