LINUX.ORG.RU

По-настоящему важный вопрос

 ,


1

3

Куда вы ставите звёздочки и амперсанды при объявлении/инициализации указателей и ссылок, и почему?

  1. T* name, T& name
  2. T * name, T & name
  3. T *name, T &name
  4. Я талиб, я везде использую передачу по значению

P.S. Это не тупой наброс, мне правда интересно кто как делает, может есть весомые причины делать так или иначе, которые открываются с опытом.

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

int* a, b, c, d;

просто в сишечке так делать не кошерно(хотя чисто технически возможно)

переменная-указатель, (исходя из требований к читаемости) должна объявляться отдельно и особо.

int a = 10;
int* p = &a; // выглядит и читается нормально

int *pa = &a, b = 30; // технически допустимая, но в смысле чтения и понимания - неудобоваримая конструкция
olelookoe ★★★
()
Ответ на: комментарий от Ivan_qrt

Это просто косяк сишки, что у этих переменных разный тип.

это у сишечки и плюшечки такая семантика списочного обьявления переменных, что говорит о том, что они считают, что в данном случае, * или & есть квалификатор самой переменной, а не часть типа.

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

переменная-указатель, (исходя из требований к читаемости) должна объявляться отдельно и особо.

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

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

int* разумеется. но не потому, что напиcан тип int*, а потому что написан тип int, а перед «а» стоит звездочка. если б звездочка была и перед «b», то тип b тоже был бы int*

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

Если бы сишка была продуманным языком - да.

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

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

Начало какой-нибудь функции в типичном старом Си-коде могло выглядеть как-то так:

int a, b, b2, i, *s, *d; char c, *pc;

И дальше в том же духе лапша с кучей арифметики на указателях и байтоё***твом.

Вот тебе и практические соображения. Особенно когда у тебя для работы с кодом - ч/б экран 80x25 знакомест.

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

А незнание теории типов тут ни при чём. В 70-80-е системными вещами тоже не дураки занимались, теоретический фундамент для различных парадигм ЯП и их систем типов уже либо прочно существовал, либо активно развивался, в зависимости от направления.

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

Сишка предоставляет много «вольготности» для программиста и полагается на то, что программисту такой код удобен/нужен.

Тут вопрос не о вольготности, а о продуманности/логичности. То, что сделано в сишке с объявлениями переменных - это тупость, а не вольготность.

Ivan_qrt ★★★★★
()

Конечно первое, потому что семантически это часть типа. Правда, синтаксически в выродке C это не так, но разница будет только в объявлении нескольких переменных в одном выражении T* name, name1;, что в любом случае обязано быть запрещено стайлгайдом. Поэтому конечно, первое.

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

Я вообще плохо понимаю, с чего кто-то подумал что * это не часть типа? Ну это же прям очевидно.

struct some_type{
...
...
...

} a, *b, **c;

ну где тут обьявлен тип - двойной указатель на структуру для ‘с’? его нет. он выводится по двум звездочкам, заносится компилятором в таблицу типов, и привязывается к ‘с’.

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

там обьявление типа-функция, а не прототипа. но не переменной.

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

Я же не учу других хаскелю или перлу.

#include <stdio.h>

static int a[2] = {0, 0};

int const * foo(double x)
{
    int *p = &a[x >= 0.0 ? 0 : 1];
    (*p)++;
    return p;
}

int main()
{
    int const * (* const f)(double) = foo;
    printf("%d\n", *f(1));
    printf("%d\n", *f(-1));
    printf("%d\n", *f(2));
    printf("%d\n", *f(-2));
    return 0;
}
wandrien ★★
()
Ответ на: комментарий от alysnix

ну где тут обьявлен тип - двойной указатель на структуру для ‘с’? его нет. он выводится по двум звездочкам, заносится компилятором ы таблицу типов, и привязывается к ‘с’.

А где тут int** a объявлен двойной указатель на int для a? Его нет. Он выводится по двум звёздочкам и далее по тексту.

Как что либо из этого меняет тот факт, что * относится к типу (является квалификатором типа) и меняет только тип?

Ivan_qrt ★★★★★
()

Раньше было так:

struct {
  unsigned int  f1;
  char const *  f2;
};
char const * func(char const * arg) {
  char const * var;
}

Теперь (года 3 назад передумал) так:

struct {
  unsigned int  f1;
  char const    *f2;
};
char const * func(char const *arg) {
  char const *var;
}
В старых проектах пишу по-старому чтобы было единообразие стиля.

На C++ с момента «переключения» ничего нового не начинал, так что там с & старый вариант аналогичный звёздочке.

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

Звёздочка около имени потому что парсер её прицепляет к имени, а не к типу:

int *a, b;  /* a - указатель, b - число */
int* a, b;  /* запутывает, кажется что оба указатели */

Около типа звёздочка потому что интуитивно хочется её прицепить к типу несмотря на реальность. Пробелы с обоих сторон - компромисс.

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

Если в структуре то понятно - каждой переменной может потербоваться комментарий. А вот если если у тебя десяток локальных переменных в функции то надо заспамливать ими 10 строк вместо одной?

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

Сомнительное удобство, такой синтаксис весьма запутывает касательно того, к чему именно относится const. Потому как есть ещё такая запись:

static int *

И она означает вовсе не «указатель на static переменную», а «static указатель».

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

Нет, просто звёздочка в объявлении переменной парсится аналогично [] для длины массива - как модификатор типа для конкретно этой переменной. Иначе было бы сложно объявлять сложные типы типа «массив указателей на массив».

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

Если бы это было часто нужно - делалось бы на интуиции легко и быстро. А так привычки нет. Но если чуть подумать то вполне можно. А ещё можно считерить - написать исходник с всякими typedef-ами и заставить компилятор вывести в логе какой-нить ошибки результирующий тип. Хотя я такое не делал никогда, зачем? Лучше эти самые typedef-ы в исходнике и оставить.

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

Нет

Что именно нет? Ты не согласен с тем, что в том примере переменная a - это указатель на целое? Или с чем ты не согласен?

просто звёздочка в объявлении переменной парсится аналогично [] для длины массива - как модификатор типа для конкретно этой переменной.

Да кто бы спорил-то. Просто это хреновое решение. Какая-то логика в этом разумеется есть, но лучше от этого не становится.

Иначе было бы сложно объявлять сложные типы типа «массив указателей на массив».

int*[5] a или int[5][6] md.

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

А вот если если у тебя десяток локальных переменных в функции то надо заспамливать ими 10 строк вместо одной?

Да.

А в плюсах объявлять переменные непосредственно перед использованием с минимальной подходящей областью жизни.

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

Вот тебе и практические соображения. Особенно когда у тебя для работы с кодом - ч/б экран 80x25 знакомест.

У меня экран больше, но это не повод транжирить место на нём на всякие украшательства. Бесит, когда то, что можно уместить на одну-две строки, растягивают в мусорную простыню на полэкрана. Какое-нить вместо

for(i=1; i<10; i++) for(j=i; j<10; j++) if(a[i][j]>5) printf("%u,%u\n", i, j);
вот такую чушь:
/* some useless
 * multiline comment */

for (i = 1; i < 10; i++)
  {
    for (j = i; j < 10; j++)
      {
        if (a[i][j] > 5)
          {
            printf ("%u,%u\n", i, j);
          }
      }
  }

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

А в плюсах объявлять переменные непосредственно перед использованием с минимальной подходящей областью жизни.

Бывает, что я еще и блоки ставлю, чтобы максимально ограничить область видимости имени.

Ну и в Си теперь тоже можно переменные везде объявлять, а не только в начале блока.

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

Так твой хороший тон выглядит in the wild:

static void on_create_new(GtkAction* act, FmFolderView* fv)
{
    _init_quarks();

    const char* name = gtk_action_get_name(act);
    GtkMenu *popup = g_object_get_qdata(G_OBJECT(fv), popup_quark);
    GtkWidget *win = gtk_menu_get_attach_widget(popup);
    GtkUIManager *ui = g_object_get_qdata(G_OBJECT(fv), ui_quark);
    GList *templates = g_object_get_qdata(G_OBJECT(ui), templates_quark);
    FmTemplate *templ;
    FmMimeType *mime_type;
    const char *prompt, *template_name, *label;
    char *_prompt = NULL, *header, *basename;
    FmPath *dest;
    GFile *gf;
    GError *error = NULL;
    GtkWidget *run_button, *sub_button;
    gboolean new_folder = FALSE, run_app;
    gint n;

    if(strncmp(name, "NewFolder", 9) == 0)
    {
        templ = NULL;
        prompt = _("Enter a name for the newly created folder:");
        header = _("Creating new folder");
        new_folder = TRUE;
    }
    else if(G_LIKELY(strncmp(name, "NewFile", 7) == 0))
    {
        n = atoi(&name[7]);
        if(n < 0 || (templ = g_list_nth_data(templates, n)) == NULL)
            return; /* invalid action name, is it possible? */
    }
    /* special option 'NewBlank' */
    else if(G_LIKELY(strcmp(name, "NewBlank") == 0))
    {
        templ = NULL;
        prompt = _("Enter a name for empty file:");
        header = _("Creating ...");
    }
    else /* invalid action name, is it possible? */
        return;
    if(templ == NULL) /* new folder */
    {
        template_name = _("New");
        n = -1;
        run_app = FALSE;
        run_button = NULL;
    }
    else
    {
        mime_type = fm_template_get_mime_type(templ);
        prompt = fm_template_get_prompt(templ);
        if(!prompt)
            prompt = _prompt = g_strdup_printf(_("Enter a name for the new %s:"),
                                               fm_mime_type_get_desc(mime_type));
        label = fm_template_get_label(templ);
        header = g_strdup_printf(_("Creating %s"), label ? label :
                                             fm_mime_type_get_desc(mime_type));
        template_name = fm_template_get_name(templ, &n);
        run_app = fm_config->template_run_app;
        sub_button = gtk_check_button_new_with_mnemonic(_("_Run default application on file after creation"));
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sub_button), run_app);
        g_signal_connect(sub_button, "toggled", G_CALLBACK(on_run_app_toggled), &run_app);
        run_button = gtk_alignment_new(0, 0, 1, 1);
        gtk_alignment_set_padding(GTK_ALIGNMENT(run_button), 0, 0, 16, 0);
        gtk_container_add(GTK_CONTAINER(run_button), sub_button);
    }
    basename = fm_get_user_input_n(GTK_WINDOW(win), header, prompt,
                                   template_name, n, run_button);
    if(templ)
    {
        g_free(_prompt);
        g_free(header);
    }
    if(!basename)
        return;
    dest = fm_path_new_child(fm_folder_view_get_cwd(fv), basename);
    g_free(basename);
    gf = fm_path_to_gfile(dest);
    fm_path_unref(dest);
    if(templ)
        fm_template_create_file(templ, gf, &error, run_app);
    else if(new_folder)
        g_file_make_directory(gf, NULL, &error);
    /* specail option 'NewBlank' */
    else
    {
        GFileOutputStream *f = g_file_create(gf, G_FILE_CREATE_NONE, NULL, &error);
        if(f)
            g_object_unref(f);
    }
    if(error)
    {
        fm_show_error(GTK_WINDOW(win), NULL, error->message);
        g_error_free(error);
    }
    g_object_unref(gf);
}
wandrien ★★
()
Ответ на: комментарий от firkax

но не того, что слева записан, а того, что будет применён к конкретной переменной.

Мда. А какой тип будет применён к переменной? Тот который записан слева с применёнными к нему квалификаторами или какой-то другой? А если именно тот, который записан слева, то с чего вдруг это не его квалификаторы, а квалификаторы чего-то другого?

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

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

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

Ну и в Си теперь тоже можно переменные везде объявлять, а не только в начале блока.

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

М.б. там имеет смысл объявлять те переменные, в которые могут выделяться какие-то ресурсы, которые нужно будет освободить, чтобы было удобнее следить за этим.
Но вот накой чёрт в начале функции объявлять int i; для меня загадка (если не используется древний стандарт, естественно).

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

Плохой тон это как раз сишка, чуть менее чем вся)

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

alex1101
() автор топика