LINUX.ORG.RU

Как правильно создавать структуры в Си? (Закрыто, FAIL, будем дальше курить литературу)

 


1

4

Накорябал такой код. Вроде всё работает, память очищается, а вот структуру приходится создавать через левые значения переменных (struct date *today = date_create (1, 1, 1);). Как это правильно делается?

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


	struct date
{
	int year;
	int month;
	int day;
};
	
struct date *date_create(int year, int month, int day)
{
	struct date *when = malloc(sizeof(struct date));
	assert(when != NULL);
		
	when->year = year;
	when->month = month;
	when->day = day;
		
	return when;
}

void date_destroy(struct date *when)
{
	assert(when != NULL);
	free(when);
}
	
void date_print(struct date *when)
{
	printf (" date is %i/%i/%i\n", when->year, when->month, when->day);
}

int main(void)
{
	const int dayspermonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	
	struct date *today = date_create (1, 1, 1);
	printf ("Enter today`s date yyyy mm dd:\n");
	scanf ("%i %i %i", &today->year, &today->month, &today->day);
	struct date *tomorrow = date_create (today->year, today->month, today->day);
	
	if (today->day != dayspermonth[today->month - 1])
	{
		tomorrow->year = today->year;
		tomorrow->month = today->month;
		tomorrow->day = today->day + 1;
	}
	
	else if (today->month == 12)
	{
		tomorrow->year = today->year + 1;
		tomorrow->month = 1;
		tomorrow->day = 1;
	}
	
	else
	{
		tomorrow->year = today->year;
		tomorrow->month = today->month + 1;
		tomorrow->day = today->day;
	}
	

	date_print(today);
	date_print(tomorrow);
	date_destroy(today);
	date_destroy(tomorrow);
	return 0;
}
★★★★★

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

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

FILE ещё куда ни шло. Капслоком набираются макросы и это как красная тряпка - за этим FILE может скрываться что угодно. Например #define FILE void - вполне нормальный вариант.

Ну и, да, FILE считаю не очень удачным дизайном. Лучше бы часть POSIX сделали С-стандартом и навернули бы всякие printf-ы на файловых дескрипторах без промежуточной прослойки.

Legioner ★★★★★
()
Ответ на: комментарий от steemandlinux
λ> cat fofofo.c
#include <stdlib.h>
#include <stdio.h>

typedef struct _DATE
{
  short year;
  char month;
  char day;

} DATE, *PDATE;

int main ()
{
  PDATE date = calloc(1, sizeof(struct _DATE));
  if (NULL == date)
    {
      return 1;
    }

  free(date);
  free(date);
  return 0;
}
λ> gcc -Wall fofofo.c -o fofofo
λ> ./fofofo
*** glibc detected *** ./fofofo: double free or corruption (fasttop): 0x0000000001687010 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x76d76)[0x7f430f1c9d76]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x6c)[0x7f430f1ceb1c]
./fofofo[0x40058d]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd)[0x7f430f171ead]
./fofofo[0x400469]
======= Memory map: ========
00400000-00401000 r-xp 00000000 fe:01 412191                             /tmp/fofofo
00600000-00601000 rw-p 00000000 fe:01 412191                             /tmp/fofofo
01687000-016a8000 rw-p 00000000 00:00 0                                  [heap]
7f4308000000-7f4308021000 rw-p 00000000 00:00 0
7f4308021000-7f430c000000 ---p 00000000 00:00 0
7f430ef3d000-7f430ef52000 r-xp 00000000 fe:01 1175044                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f430ef52000-7f430f152000 ---p 00015000 fe:01 1175044                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f430f152000-7f430f153000 rw-p 00015000 fe:01 1175044                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f430f153000-7f430f2d5000 r-xp 00000000 fe:01 1175043                    /lib/x86_64-linux-gnu/libc-2.13.so
7f430f2d5000-7f430f4d4000 ---p 00182000 fe:01 1175043                    /lib/x86_64-linux-gnu/libc-2.13.so
7f430f4d4000-7f430f4d8000 r--p 00181000 fe:01 1175043                    /lib/x86_64-linux-gnu/libc-2.13.so
7f430f4d8000-7f430f4d9000 rw-p 00185000 fe:01 1175043                    /lib/x86_64-linux-gnu/libc-2.13.so
7f430f4d9000-7f430f4de000 rw-p 00000000 00:00 0
7f430f4de000-7f430f4fe000 r-xp 00000000 fe:01 1175066                    /lib/x86_64-linux-gnu/ld-2.13.so
7f430f6d1000-7f430f6d4000 rw-p 00000000 00:00 0
7f430f6fb000-7f430f6fd000 rw-p 00000000 00:00 0
7f430f6fd000-7f430f6fe000 r--p 0001f000 fe:01 1175066                    /lib/x86_64-linux-gnu/ld-2.13.so
7f430f6fe000-7f430f6ff000 rw-p 00020000 fe:01 1175066                    /lib/x86_64-linux-gnu/ld-2.13.so
7f430f6ff000-7f430f700000 rw-p 00000000 00:00 0
7fff37ed2000-7fff37ef3000 rw-p 00000000 00:00 0                          [stack]
7fff37fa0000-7fff37fa2000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
[1]    17049 abort      ./fofofo

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

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

Не использовал, не использую и не буду использовать (надеюсь) никогда! Потому что я — не погромист никакой!

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

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

Да уж, жестко. И компилятор даже не хрюкнул.

steemandlinux ★★★★★
() автор топика
Ответ на: комментарий от Eddy_Em
#define FREE(x) do{free(x); x = NULL;}while(0)

Так ты просто ошибку скрываешь, обычно указатели, наоборот, отравляют:

#define FREE(x) do{free(x); x = 0xC001FACE;}while(0)

впрочем, кому я рассказываю!

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

Тебе struct лень написать? Зачем делать неявный код? Зачем скрывать struct за обычным именем?

по-моему, ты предлагаешь использовать какую-то особо длинную венгерскую нотацию для типов. а чего ты тогда пишешь foo(a,b), а не foo(int a,int b), как, скажем, в llvm ir?

Зачем загрязнять глобальный namespace?

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

Если бы создатели С хотели ... понимали ...

«создатели C» его создавали в известное время для известного железа и применений, и они много чего хотели и понимали, только далеко не всё из этого актуально сейчас. я в своё время с деннисом на эту тему общался (в 2000-е) — он полностью отдавал себе отчёт, что дизайн си — это артефакт существовавших на тот момент требований (как и дизайн любого хорошего инструмента). см., скажем, http://cm.bell-labs.com/cm/cs/who/dmr/chist.html (сейчас опять, кажется, файловый сервер выдернули из розетки).

второй из «создателей C» как раз с недавних пор в гугле занимается пересмотром дизайна языка.

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

Чтобы на препроцессоре это сделать, надо строчки четыре-пять. А тут одна. :-)

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

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

И в «один прекрасный момент» ты получишь тыкву вместо кареты!

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

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

Нет-нет, я предлагаю делать #define MACROS { xxx; yyy; }

вместо #define MACROS do { xxx; yyy; } while(0)

, с твоим примером должно раскрыться нормально. А вот break не сделаешь, да.

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

В моем случае все ОК. А вот в твоем — жопа.

Это экспертная оценка? Тыж «непрограммист». :)

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

За typedef struct {..} XXX надо отрывать руки.

Рили?

Тебе struct лень написать?

Да.

Зачем делать неявный код?

Чем он не явный?

Зачем загрязнять глобальный namespace?

Т.е. ты будешь юзать одно и тоже имя и для структуры и для чего-то ещё? Куллстори. А если не одно, то какая разница?

Если бы создатели С хотели, чтобы struct-ы писались без struct, они бы просто так сделали по умолчанию, как страуструп сделал.

Мне по твоему ещё unsigned писать?

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

И что это меняет? На что эти сотни байт влияют?

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

Когда вложишь саму в себя, один хрен форвард по тегу делать. Стайл поломаешь :)

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

Нормально работает. До первого сегфолта =D

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от AptGet

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

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

Ты, похоже, тоже не понял смысла макроса FREE(). После этого макроса я смогу проверять валидность указателя. А без него — нет!

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от oneliner
void  _prefault(uint64_t size) {
  uint64_t _64kb = 64 * 1024;
  do {
    void * volatile ptr = malloc(_64kb);
  } while((size -= _64kb) >= _64kb);
}


int main(void) {
  _prefault(4ul * 1024 * 1024 * 1024);
  uint32_t * infa100 = 0xC001FACE;
  *infa100 = 0xFA11FACE;
  fprintf(stderr, "%x\n", *infa100);
}

# ./a.out 
fa11face

Куллстори.

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

Кстати, а как функцию и возврат этой структуры сделать?

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

А всё, разобрался. Я тормоз, одну и ту же структуру отправляю и возвращаю :D

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