Страницы

Поиск по вопросам

Показаны сообщения с ярлыком синтаксис. Показать все сообщения
Показаны сообщения с ярлыком синтаксис. Показать все сообщения

пятница, 31 января 2020 г.

Как работают операции &~ в C

#c #синтаксис


int y = 2, x = 3, z = 1, k;
k = y&~z; 


Как здесь получается значение 2? Как работают эти операции &~?
    


Ответы

Ответ 1



Значение y равно 2, что в двоичном представлении выражается набором битов 00..010. Значение z равно 1, что в двоичном представлении выражается набором битов 00..001. Применение операции инверсии битов ~ к значению z дает набор битов 11..110. Затем операция побитового-И & применяется к двоичным представлениям y и ~z, т.е. к 00..010 и 11..110 соответственно, что дает в результате двоичное представление 00..010. А это двоичное представление все того же 2. Отдельно стоит заметить, что побитовые манипуляции лучше производить с беззнаковыми типами, если нет специальной необходимости использовать знаковые типы.

вторник, 28 января 2020 г.

Разница между define и const [дубликат]

#cpp #c #синтаксис


        
             
                
                    
                        
                            На этот вопрос уже даны ответы здесь:
                            
                        
                    
                
                        
                            Различие define и const
                                
                                    (2 ответа)
                                
                        
                                Закрыт 2 года назад.
            
                    
В чем в C++ разница между #define и const? То есть какой из вариантов предпочтительнее
и в какой ситуации, есть ли вообще разница?
    


Ответы

Ответ 1



#define - это макрос препроцессора, он просто выполняет замену строки текста на своё содержимой. До c++11 его имело смысл использовать для глобальных численных констант. const - это квалификатор типа, говорящий, что переменная не должна меняться после инициализации. Но эта инициализация где-то должна произойти, и от константности можно вручную избавиться при помощи const_cast. В c++11 был добавлен квалификатор constexpr, который указывает на то, что переменная может как-то изменяться только во время компиляции, но не во время выполнения. Детали зависят от версии стандарта. Теперь можно без проблем объявлять статические константы, в том числе сложных типов. Например: namespace constants{ static constexpr double g = 9.8; struct minus_fn_impl{ template T operator () (const T& lha, const T& rha){ return lha - rha; } }; static constexpr minus_fn_impl minus_fn; } ... double v = 5.3; double r = constants::minus_fn(v, constants::g); // не нужно инициализировать функциональный объект, как в случае std::minus

Ответ 2



Конечно, есть. Хотя бы в том, что const дает возможность проверки типов. Компилятор знает, что такое const, и разбирается, на своем ли он месте. О #define знает только препроцессор. Так что - всегда предпочтительнее const.

Ответ 3



#define - это препроцессорная директива; препроцессор заменяет все эти макросы во время компиляции. const переменные - это фактические переменные языка. Плюсы констант в проверке типов и т.п, как пример. В целом, насколько я могу судить, в итоге получаем одно и то же. Разве что, у define'ов нету области видимости, а у констант есть.

Ответ 4



Разница вот в чём: definы компилятор просто подставляет во время компиляции, т.е. пишешь такой код: #define NAME "Alex" ... std::cout << NAME И когда ты запускаешь компиляцию, компилятор сначала преобразует это в: std::cout << "Alex" И только потом компилирует. А вот, когда ты используешь const, создаётся обычная переменная, только её нельзя изменять, т.е. если тв попробуешь её изменить, компилятор выдаст ошибку

Ответ 5



Использовать #define только там, где нет возможности использовать const (constexpr в c++11). То есть, для определения констант #define уже достаточно давно использовать не рекомендуется.

пятница, 10 января 2020 г.

неименованное объединение в структуре

#c #синтаксис


Подсмотрела у коллег в проекте примерно вот такую конструкцию:  

struct A {
  int i;
  union {
    char j;
    double k;
  };
} a;
...
a.j = 'a';


Проект на С, компилируется под gcc.
Нашла описание подобного использования union для плюсов, но вот для С такого (использование
объединения без имени с упрощенным доступом к его полям) мне раньше не попадалось.

Это допустимая для С конструкция, или это одна из особенностей gcc? При переходе
на другой компиллятор с ней проблем не возникнет?
    


Ответы

Ответ 1



Это вполне совместимая со стандартом C, начиная с C11, конструкция. MSVC, который достаточно слабо поддерживает стандарт C, её тем не менее прекрасно понимает. В стандарте C99 этой конструкции не было, но gcc тем не менее поддерживал её как расширение языка. Википедия: The standard includes several changes to the C99 language and library specifications, such as: Anonymous structures and unions, useful when unions and structures are nested, e.g. in struct T { int tag; union { float x; int n; }; };. Ссылка на стандарт, §6.7.2.1/13: An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure; an unnamed member whose type specifier is a union specifier with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.

понедельник, 6 января 2020 г.

Синтаксис перегрузки операторов C#

#c_sharp #перегрузка_операторов #синтаксис


Подскажите, пожалуйста, почему метод перегружающий оператор должен быть обязательно
public и static?
    


Ответы

Ответ 1



Давайте создадим тестовый класс и перегрузим оператор сложения для него: public class MyClass { public int A { get; set; } public static MyClass operator +(MyClass A, MyClass B) { return new MyClass { A = A.A + B.A }; } } А теперь посмотрим, какие методы декларирует наш класс: MethodInfo[] methods = typeof(MyClass).GetMethods(); Среди прочего в массиве methods мы увидим такую запись: MyClass op_Addition(MyClass, MyClass) Условно, когда вы перегружаете оператор, создается метод с указанным названием и атрибутами Public | Static | HideBySig | SpecialName. Так что следующий код: MyClass a = new MyClass { A = 1 }; MyClass b = new MyClass { A = 2 }; MyClass c = a + b; На деле преобразуется в: MyClass a = new MyClass { A = 1 }; MyClass b = new MyClass { A = 2 }; MyClass c = MyClass.op_Addition(a, b); Как видите, когда Вы описали оператор, Вы создали статическую функцию с именем op_Addition. Статическая она по той причине, что в C# не предусмотрен вариант типа public MyClass operator +(MyClass B) { return new MyClass { A = this.A + B.A }; } Да и это не нужно, так как статическим вариантом можно покрыть любую свою нужду. Так что плодить какие-то дополнительные методы с теми же возможностями - бессмыленно.Почему синтаксис C# не предусматривает приватные перегруженные операторы? По той же причине, по которой он не поддерживает методы с одинаковыми параметрами, но разными модификаторами доступа: компилятор не сможет понять, какую именно функцию Вы захотите использовать в некотором контексте.

понедельник, 30 декабря 2019 г.

Двойные и одинарные кавычки

#java #синтаксис


Не нашёл ответ в инете:
почему в Java двойные кавычки используются только для строк , а одинарные только
для символов?
В чём профит?    


Ответы

Ответ 1



Профит в том, чтобы чётко различать литералы строк и символов. Если бы и строки, и символы можно было задавать с помощью одного и того же типа кавычек, то пришлось бв проверять, символ ли это, или строка. Иногда это вносило бы путаницу, а иногда точно определить это не представлялось бы возможным. Вот пример: public void doSth(String s) {} public void doSth(char c) {} doSth("a"); Если бы литералы символов можно было задавать с помощью двойных кавычек, тут возникла бы неопределённость: какой метод вызывать?

воскресенье, 22 декабря 2019 г.

Инкременты и сложения

#java #синтаксис


Вот такой код компилируется в Java без ошибок:

public class Test {
    public static void main(String[] args) {
        int a = 2, b = 3;
        System.out.println(a+++--b);
        System.out.println(a++-++b);
        System.out.println(a---++b);
        System.out.println(a--+--b);
    }
}


А вот тут ни одна строчка с println не компилируется:

public class Test {
    public static void main(String[] args) {
        int a = 2, b = 3;
        System.out.println(a--+++b); // error: unexpected type
        System.out.println(a++---b); // error: unexpected type
        System.out.println(a+++++b); // error: unexpected type
        System.out.println(a-----b); // error: unexpected type
    }
}


Почему так? Ну может последние две ещё сильно сложно разобрать, но первые-то почти
такие же как в работающем примере?
    


Ответы

Ответ 1



Думаю, проблема вот в чём. Компилятор Java сначала разбивает текст на токены (лексический анализ), а потом пытается понять его значение (синтаксический). Судя по всему, разбиение происходит строго слева направо. При этом ++, --, + и - являются отдельными токенами. При чтении первого примера происходит следующее разбиение: a+++--b => a ++ + -- b (поскольку после токена ++ самым длинным возможным токеном является лишь +). Это интерпретируется как (a++) + (--b). Для неработающего случая происходит следующее разбиение: a--+++b => a -- ++ + b — а это невозможно сгруппировать в валидный синтаксис, так как и слева, и справа от ++ находятся выражения, не являющиеся Java-аналогом lvalue. Подтверждение из JLS: A translation of the stream of input characters and line terminators resulting from step 2 into a sequence of input elements (§3.5) which, after white space (§3.6) and comments (§3.7) are discarded, comprise the tokens (§3.5) that are the terminal symbols of the syntactic grammar (§2.3). The longest possible translation is used at each step, even if the result does not ultimately make a correct program while another lexical translation would. Ниже в документации расположен как раз подходящий пример: The input characters a--b are tokenized (§3.5) as a, --, b, which is not part of any grammatically correct program, even though the tokenization a, -, -, b could be part of a grammatically correct program. Перевод (мой): Преобразование потока входных символов и символов окончания строки, получившегося на шаге 2, в последовательность входных элементов(§3.5), которые, после удаления пробелов (§3.6) и комментариев (§3.7), формируют токены (§3.5), являющиеся терминальными символами грамматики языка (§2.3). На каждом шаге выбирается самое длинный возможный токен, даже если результат в конечном итоге не будет корректной программой, хотя бы даже при другом разбиении на токены получилась корректная программа. Входные символы a--b разбиваются на токены (§3.5) как a, --, b, что не является частью синтаксически корректной программы, хотя разбиение a, -, -, b могло бы быть таковым.

четверг, 19 декабря 2019 г.

Что означает разговорное выражение «синтаксический сахар»?

#синтаксис #терминология #любой_язык


В видео-уроках встретилось выражение у автора синтаксический сахар, что оно означает?
    


Ответы

Ответ 1



Словосочетание "синтаксический сахар" используется для описания синтаксических конструкций, которые вводятся только для упрощения реализации чего-либо (сокращения объема кода, повышения читаемости и т.д.) в том или ином языке. При этом, без синтаксического сахара вполне можно обойтись, но реализация без его использования получится более громоздкой (сложной, непонятной, ...). Типичный пример - новый синтаксис для стрелочных функций в ES6: var f = x => x*x; В ES5 эту конструкцию можно записать так: var f = function(x) { return x*x; } Для любителей JS отмечу, что стрелочные функции еще и контекст вызова "привязывают" автоматически, но в данном конкретном примере это не существенно. Подробнее см. Википедию.

Ответ 2



Синтаксический сахар - конструкция языка, которая полностью дублирует уже имеющиеся возможности, но при этом обладает преимуществом в удобстве/краткости/похожести/стилистике. В данном случае "тернарный оператор if" полностью совпадает с типичным if-else и присваиванием, но немного короче. a = x != 0 ? a/x : 0; аналогично, но короче чем if(x != 0){ a /= x; } else { a = 0; }

воскресенье, 15 декабря 2019 г.

Java методы, сокращенные до выражений

#java #c_sharp #синтаксис


В C#, начиная с версии 6.0, метод, который только возвращает значение:

public int func(int x)
{
    return x*x;
}


Можно сократить до выражения (expression-bodied member):

public int func(int x) => x*x;


Существуют ли подобные сокращения в Java?
    


Ответы

Ответ 1



Нет, объявления членов класса с помощью выражения в Java нет. В последней спецификации Java 9 в синтаксисе объявления метода явно указано тело: MethodDeclaration: {MethodModifier} MethodHeader MethodBody И предложения такого для Java я не нашел. Можете посмотреть в сторону языка Kotlin, он работает под JVM и предоставляет много синтаксического сахара, в том числе объявление функции: fun sum(a: Int, b: Int) = a + b

суббота, 14 декабря 2019 г.

javascript, замыкания, проблемы синтаксиса

#javascript #синтаксис #замыкания


Есть код на JavaScript:

"use strict";

var site = (function ()
{
    var loader_html = '';
    var loader_image_width = 100;
    var loader_image_height = 100;

    return
    {
        window_subroutines : {
            get_scrollTop : function () { return (document.documentElement && document.documentElement.scrollTop)
|| (document.body && document.body.scrollTop); },
            get_scrollLeft : function () { return (document.documentElement && document.documentElement.scrollLeft)
|| (document.body && document.body.scrollLeft); },
            get_clientWidth : function () { return (document.documentElement && document.documentElement.clientWidth)
|| (document.body && document.body.clientWidth); },
            get_clientHeight : function () { return (document.documentElement &&
document.documentElement.clientHeight) || (document.body && document.body.clientHeight); }
        },

        loader : {
            show : function () {
                var loader_elem = document.getElementById ("loader_container");
                var left_coord = Math.round(site.window_subroutines.get_scrollLeft()
+ ( site.window_subroutines.get_clientWidth() / 2 ) - ( loader_image_width / 2 )) + "px";
                var top_coord = Math.round(site.window_subroutines.get_scrollTop()
+ ( site.window_subroutines.get_clientHeight() / 2 ) - ( loader_image_height / 2 )) + "px";

                loader_elem.innerHTML = loader_html;
                loader_elem.style.top = top_coord;
                loader_elem.style.left = left_coord;

                loader_elem.style.display = "block";
            },

            hide : function () { setTimeout("document.getElementById('loader_container').style.display
= 'none';", 750); }
        }
    };

})();


Проблема в том, что при попытке его выполнить браузер выводит ошибку:


  SyntaxError: function statement requires a name
  
  get_scrollTop : function () { return (document.documentElement && document.docum...


Посмотреть живьём это можно на jsfiddle
    


Ответы

Ответ 1



Надо изменить return { на return { JavaScript добавляет ; в конец строка автоматическим образом, так что код распарсится так: return; { // блок кода window_subroutines: // метка { // блок кода get_scrollTop : // метка function () { /* ... */ } // SyntaxError: декларация функции без имени (Смотрите в спецификации о инструкциях с метками и автоматической подстановке точки с запятой)

четверг, 12 декабря 2019 г.

Указатель на указатель - что это?

#указатели #синтаксис #cpp


Часто встречаю вот такую конструкцию: 
int ** p;

Я так понимаю, что это указатель на указатель. Зачем такая двойственность нужна и
где применяется?    


Ответы

Ответ 1



Указатель в C — не семантика, а механизм. Он сам по себе не несёт смысла, но может использоваться для выражения того или иного смысла. То же относится и к двойному указателю: он может использоваться для разных вещей. Вот несколько примеров. В C параметры передаются по значению, то есть из коробки нету передачи параметров «по ссылке» (они же &-параметры C++, они же ref-/out-параметры C#). Для того, чтобы объявить такой параметр, пользуются указателем на фактический параметр (то есть, передают в функцию адрес параметра). Если тип самого параметра — указатель, получается двойной указатель. Пример: void split_half(char* input, char** first_half, char** second_half) { var len = strlen(input); var halflen = len / 2; *first_half = malloc(halflen + 1); strncpy(*first_half, input, halflen); (*firsthalf)[halflen] = 0; *second_half = strdup(&input[halflen]); } В C указатель может обозначать массив. Если тип элемента массива — указатель, получается двойной указатель. Классический пример: int main(int argc, char** argv) { ... } Двойной указатель можно использовать для массива массивов. Например, квадратная матрица: struct matrix { int** data; int width; int height; } void init_matrix(int width, int height, struct matrix* matrix) { matrix->width = width; matrix->height = height; matrix->data = malloc(height * sizeof(int*)); for (int y = 0; y < height; y++) matrix->data[y] = malloc(width * sizeof(int)); } В C++ обычно ручное управление памятью не приветствуется, поэтому там кратные указатели встречаются куда реже.

Ответ 2



Ни в языке С++, ни в языке С, нет такого понятия, как "указатель на указатель" в виде самостоятельной сущности с какими-то новыми качественными свойствами. Поэтому в строгом смысле слова, вопрос о том "зачем нужен указатель на указатель" не имеет никакого смысла. В языках С и С++ есть такое понятие, как указатель. Просто указатель. Т.е. если у вас есть некий тип T, то вы можете объявить указатель p на этот тип T *p; и заставить этот указатель указывать на объект t типа T T t; p = &t; После этого выражения t и *p будут обозначать один и тот же объект. Т.е. если вы, например, поменяете значение объекта *p, то тем самым вы поменяете и объект t (и наоборот). Вы можете также завести еще сколько угодно указателей на один и от же объект. Это - элементарные основы идеи указателя. Ну так а далее можно просто заметить, что тип T сам по себе может быть указательным типом. Но это совершенно ничего не меняет. Нет ничего принципиально разного между ситуацией, когда T - это int, и ситуацией, когда T - это double *. Все вышесказанное относится к обоим случаям в одинаковой мере. Вот, собственно и все. Т.е. нет никакого смысла вводить в рассмотрение такую сущность, как "указатель на указатель", и устраивать вокруг нее какие-то обсуждения. Все, что нам нужно - это обычный указатель, который может просто-напросто указывать и на другой указатель. Но эти два уровня указательности (три, четыре, пять уровней...) совершенно отдельны, ничего о друг друге не знают и знать не хотят. И рассматривать такие указатели надо как обычные указатели. То же самое в полной мере справедливо и об "указателях на указатели на указатели", "указателях на указатели на указатели на указатели" и т.д. до бесконечности.

Ответ 3



Когда-то объяснял это на примере холодильника. int **fridge; // Холодильник с полочками на которых еда *fridge; // Полочка в холодильнике **fridge; // Колбаса

Ответ 4



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

вторник, 10 декабря 2019 г.

Ошибка lvalue required as left operand of assignment

#c #указатели #синтаксис


Есть три (независимые) строчки кода:

1) *a++ = 5;
2) *(a++) = 5;
3) (*a)++ = 5;


Первая и вторая строчки работают одинаково.
На третью компилятор (minGW, GCC) ругается:


  lvalue required as left operand of assignment
       (*a)++=5;


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

((*a) + 1) = 5;


Только в таком случае действительно не выполняется условие lvalue.

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


Ответы

Ответ 1



*a++ = 5; Сначала применение ++ к a, возврат старого указателя, разыменование, присвоение. *(a++) = 5; Сначала инкремент, который возвращает старый указатель, который разыменовывается, и по этому адресу выполняется присваивание (все, как в первой строке). (*a)++ = 5; Разыменование, получаем значение, к которому применяем ++... к чему? К разыменованному значению указателя? OK, но что при этом вернуть? Просто старое значение в памяти по этому адресу? Ссылок в C нет, это не C++. Значит, вернуть просто старое значение 5? Но это не lvalue! на что, сообственно, и указывает компилятор.... По-моему, так (с) Пух

воскресенье, 1 декабря 2019 г.

Как вставить(экранировать) переменную в место перед точкой JS

#javascript #jquery #синтаксис #экранирование


В переменной itemNumber хранится число
Есть объекты типа cart.name1.price, cart.name2.price

Как поместить/подставить переменную на место числа? Может как-то экранировать надо?

cart.name+itemNumber+.price - ругается на точку после +
    


Ответы

Ответ 1



Для этого надо использовать скобочную нотацию cart["name"+itemNumber].price

среда, 27 ноября 2019 г.

Почему const и goto не используются в java?

#java #синтаксис #константа #goto


Давайте поговорим о двух зарезервированных, но неиспользуемых ключевых словах языка
Java — const и goto. Почему они не используются? Как я понял const можно заменить на
public static final, но как быть с goto?
    


Ответы

Ответ 1



Обновление В спецификации Java (§3.9. Keywords) указана причина резервирования const и goto, не связанная с планами на будущее: The keywords const and goto are reserved, even though they are not currently used. This may allow a Java compiler to produce better error messages if these C++ keywords incorrectly appear in programs. Ключевые слова const и goto зарезервированы, хотя на данный момент не используются. Это позволит компилятору Java выводить более ясные сообщения об ошибках если эти ключевые слова C++ будут неправильно использоваться в программах. Т.о. разработчики Java изначально не имели планов использовать эти слова, а зарезервировали их чтобы отловить ошибки при копировании кода, написанного на C++ (если бы переменные можно было бы назвать goto либо const, то скопированный код C++ мог ошибочно пройти компиляцию и привести к неожиданным результатам при исполнении). Эта часть спецификации не изменялась с первого издания JLS. Ниже первоначальная версия ответа, в которой рассматриваются попытки найти применение для const и goto в Java. Многа букав: const и goto перешли из C++. Ключевым словам не нашли применения в Java. Функции, которые они выполняют в C++, в Java реализованы по-другому. История Исторически синтаксис Java основан на C++, поэтому разработчики приняли решение зарезервировать ряд ключевых слов C++, чтобы: отловить ошибки при копировании кода, написанного на C++; использовать их в дальнейшем при расширении языка; упростить переход на Java для C++-разработчиков. const и goto Таким образом вопрос сводиться к следующему: «Есть ли в Java необходимость в const и goto и что они должны делать?» const Одно из предложений ввести const по аналогии с C++ можно посмотреть по ссылке: JDK-4211070 : Java should support const parameters (like C++) for code maintainence Предложение было закрыто в 2005 году. По ссылке можно посмотреть разбор, в выводах которого отмечаются проблемы, связанные вводом const: Adding const is too late now. Had this been added from 1.0, the situation could have been different. Const pollution: the C++ approach requires all const methods to be marked with a const keyword. This means that most methods will have to be marked const explicitly. This tend to clutter all methods in C++. Compatibility is a very important feature of the JDK. Arguably, the collection classes should be modified to indicate that the elements are const. That would require all existing implementations to be updated in the same way, effectively breaking all existing non-JDK implementations of the collection interfaces. Similarly, hashCode would have to be const, breaking the current implementation of String. Создание константных переменных/полей в Java уже обеспечивается с помощью final. Ввод механизмов из C++ посчитали неоправданным. goto У goto плохая репутация (см. «Go To Statement Considered Harmful» Дейкстры). В Java имеются альтернативные операторы перехода: break, continue, return, которые покрывают большую часть области применения. Единственный довод в пользу goto состоит в том, что в отдельных случаях использование goto позволяет упростить код. По-видимому, сторонники goto не смогли оказать достаточного влияния на разработчиков, чтобы добавить новое ключевое слово. Похожие обсуждения в англиской версии: Why is there no Constant feature in Java? Is there a goto statement in Java?

Ответ 2



goto считается "плохим оператором", ухудшает читаемость и увеличивает запутанность кода, порождает трудноподдерживаемый "спагетти-код" (также нарушает очень важные концепции программирования, можно ознакомиться по ссылке в конце ответа). Некоторые серьезные люди считают, что ему нет места в языках программирования, и пишут об этом целые книги. Так вот, пока кто-то говорит об этом, создатели Java - делают. Они искренне считают, что без безусловного перехода мир станет чуточку добрее, и по совокупности проблем и преимуществ с ними можно согласиться. Подробнее Само же слово было зарезервировано на этапе создания языка, перекочевав из других популярных в то время. Так и болтается до сих пор... PS: в Java все же есть безусловные переходы, реализуемые через операторы break и continue с метками. Как часто вы ими пользовались и знали ли об этой возможности вообще (это по поводу нужности этого оператора)?

Ответ 3



Например они могут не использовать, но быть в языке, как задел на будущее, что бы в последующих версиях можно было легко добавить этот оператор и не пересечься с названием переменных/объектов в уже написанном(Legacy) на старой версии языка коде. В JavaScript, вроде, такая же практика. Касательно const, который можно заменить public static final: Ничего не мншает разработчикам JAVA в будущем реализовать const и добавить так называемых "синтаксический сахар", когда можно делать и так и так, и в итоге программа будет одинаково выполняться. Например, в C# много синтаксического сахара: Можно объявлять переменные по алиасу(int) или по самому типу(Int32) Есть LINQ, который позволяет в простых случаях обходится без циклов и т д...

Объясните мне пожалуйста, зачем нужно всегда ставить { и }

#синтаксис #code_style


Здравствуй, я не понимаю зачем все говорят что нужно всегда использовать { и }
Вот например код:

if(1>2)
{
    test = true;
}


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

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

Лично мне намного быстрее и удобнее разобрать вот такой код:

if ($a === $b) bar();
elseif($a > $b) $foo->bar($arg1);
else BazClass::bar($arg2, $arg3);


Чем:

if ($a === $b)
{
    bar();
} elseif ($a > $b)
{
    $foo->bar($arg1);
} else
{
    BazClass::bar($arg2, $arg3);
}

    


Ответы

Ответ 1



Ответ на самом деле зависит от языка. Некоторые языки (javascript, I'm looking at you) практически требуют специальной расстановки скобок, в их отсутствие код может распарситься неочевидным образом. В остальных языках-с-фигурными-скобками (C/C++/Java/C#/...) расстановка скобок — личное дело каждого, вопрос вкуса. Я лично стараюсь опустить скобки где только возможно, например, в коде if (x > 0) x = -x; Другим, наоборот, нравится наличие скобок, так как это позволяет коду if (x > 0) { x = -x; } if (y > 0) { y = -y; z = x; } выглядеть однообразно. Мой совет — пишите код так, чтобы форматирование подчёркивало вашу мысль. Например, симметрию внутренних структур кода. Это самое главное. Наличие или отсутствие скобок не сделают вас плохим программистом, отсутствие стиля вполне может. Важный отдельный случай — это наличие общего стиля команды. Если во всей команде принято ставить (или не ставить) дополнительные скобки, вам придётся придерживаться общего стиля.

Ответ 2



Практика всегда ставить скобки избавляет вас от досадных глупых ошибок. Страшилка 1. Жил-был метод с guard condition: if(somethingBad()) return; В один прекрасный день вы собираетесь домой, вас просят быстренько добавить логгирование туда. Ткнули по кнопкам (может быть даже по хоткею для live template), закоммитили: if(somethingBad()) log.error("Something bad happened"); return; И ушли. А кто-то потом тратит пару часов, чтобы найти эту невзрачную ошибку. Страшилка 2. Жил был код: if (reallyRareCondition()) handleIt(); doImportantThings(); Однажды джуниора попросили временно убрать обработку Очень Редкого Случая. Он смело закомментировал соответствующую строку и ушел играть в кикер с коллегами. if (reallyRareCondition()) // handleIt(); doImportantThings(); А потом вдруг Что-то Очень Важное перестало работать кроме редких случаев. PS. Все совпадения не случайны, а действующие лица не выдуманы.

Ответ 3



Лично я не понимаю зачем открытие скобки писать на новой строке, что бы занять ещё одну лишнюю строку? Наличие скобок и способ их расстановки это не просто вопрос стиля или личных предпочтений. Сейчас многие удивяться, но в javascript код в зависимости от расстановки скобок выполняется по разному. Смотрите фокус: function sample1() { return { foo: 'test' }; } function sample2() { return { foo: 'test' }; } alert(sample1()); // object alert(sample2()); // undefined! и это не баг :)

Ответ 4



зачем писать скобки. это от языка программирования зависит. В с/с++ скобки можно не писать, если дальше будет один оператор. А в от в перл в подобной конструкции скобки нужно писать (если только не инфиксный оператор), потому что там такой синтаксис. Но некоторые считают, что писать нужно в любом случае - так как в будущем может появится ещё одна строка внутри if и придется дописывать скобки. Так же лично я не понимаю зачем открытие скобки писать на новой строке, что бы занять ещё одну лишнюю строку? тут нужно отталкиваться от стандартов, принятых в Вашей компании или личных предпочтений (для своего кода). На мой взгляд это неправильно, возможно вы меня сможете в этом переубедить? на мой взгляд, правильнее писать указанный код так: if ($a === $b) { bar(); } elseif ($a > $b) { $foo->bar($arg1); } else { BazClass::bar($arg2, $arg3); } А Ваши два варианта не пройдут кодревью. Но зачем мне Вас переубеждать. Пока Вы пишете код для себя - пишите как хотите, хоть по слову на строку. А вот когда пишете код для компании - тут нужно следовать правилам. Зарплата может быть хорошим инструментом переубеждения.

Ответ 5



if(1>2) { test = true; } Зачем тут писать скобки? Лично я в таких случаях обычно не ставлю. Могу поставить, если дальше идёт блок else со скобками, да и то не всегда. Почти всегда ставлю в js (и джаве) - там, где принято стаить открывающую на той же строке. Многие говорят что для читаемости, но любой программист знает о таком написании, зачем же увеличить код? Дело в том, что такие выражения как правило идут среди другого кода, а не сами по себе. Соответственно, скобки явно выделяют блок, который относится к условию. Например: DoSmth1(); DoSomeOtherMagic(); if(x>7) Logger.Log(x); DoSmth(x, 2, 12, y, temp); DoALotOfOtherStuff(x); С какой вероятностью, радактируя этот код, можно случайно неправильно внести строчку в if или закомментировать имеющуюся там? Мне тоже рассказывали про реальные случаи, что комментировали логирование и следующая команда попадала в if. Как же пытаются решить эту проблему? Говорят, всегда ставим скобки. В таком случае получеается такой код: DoSmth1(); DoSomeOtherMagic(); if(x>7) { Logger.Log(x); } DoSmth(x, 2, 12, y, temp); DoALotOfOtherStuff(x); Да, здесь уже значительно сложнее ошибиться и как-то не так поступить с этим блоком. Но написан ли этот код красиво? На мой взгляд, нет. Это по прежнему мешанина вызовов методов и проверки условия. Причём, блок кода мы выделили, но таким образом мы ещё и отдалили вызываемый метод от условия. А вот как бы я отформатировал этот же код: DoSmth1(); DoSomeOtherMagic(); if(x>7) Logger.Log(x); DoSmth(x, 2, 12, y, temp); DoALotOfOtherStuff(x); Здесь нет скобок, но я потратил те же две строки, чтобы сделать вертикальные отступы. При редактировании такого кода, по сравнению с первым, гораздо сложнее ошибиться при его изменении, блок с условием заметно отделяется от остального кода, а содержимое блока идёт рядом с условием, а не отодвингается от него при помощи скобок. зачем все говорят что нужно всегда использовать { и } Потому что это проще сказать. Сказать, "пишите код в читаемом виде" - это как ничего не сказать - автор почти всегда скажет, что его код читаемый. А обговаривать все условия - это сложно. Например, я всегда ставлю скобки, если есть вторая строка - даже если она комментарий. Сейчас почти для всех языков IDE имеют автоформатирование. Для чего? Для того ли, чтобы было быстрее писать код? Или всё-таки для того, чтобы более или менее читаемый код мог писать кто угодно? Почему чем язык распространённее (и, в некоторой мере, проще), тем строже правила автоформатирования? Посмотрим на дефаултные настройки в Visual Studio. Для C++ (если я не ошибаюсь) нет автоматического добавления пробелов вокруг бинарных операторов. В C# есть. В VB.NET принудительное жёсткое форматирование отступов при уходе со строки. Случайность ли это? Вот мне кажется, что вряд ли. Почему предлагается всегда ставить пробелы у бинарных операторов? Какой вариант читаемее y = a*x*x + b*x + c; или y = a * x * x + b * x + c;? На мой взгляд первый. Тогда зачем? Да чтобы защититься от такого: y=a*x*x+b*x+c;. Так же и со скобками - это лёгкий путь предотвратить ошибки. Но лёгкий - не значит лучший. В IDE всё больше фич автоформатирования (которые, кстати, иногда бесят, когда ты хочешь внести изменение в одну строчку, а файл отформатирован не под текущий профиль), но вот отступы в виде пустых строк сами делаться не умеют. Да и в стайл-гайдах очень редко это прописывается. Точнее, часто для css и подобных, возможно ещё, отступы между функциями, но больше ничего не упоминается. Выравнивание кода в столбцы (про которое тоже недавно был вопрос) тоже упоминается крайне редко. Ну и ещё примерчик. Что лучше? if(user.HasRole("Admin")) { return SomeAdminData(); } if(user.HasRole("Moderator")) { return SomeModeratorData(); } if(user.HasRole("User")) { return SomeData(); } return SomeAnonimousData(); или всё-таки if(user.HasRole("Admin")) return SomeAdminData(); if(user.HasRole("Moderator")) return SomeModeratorData(); if(user.HasRole("User")) return SomeData(); return SomeAnonimousData(); но мне бы как-то не хотелось увидеть if(user.HasRole("Admin")) return SomeAdminData(); if(user.HasRole("Moderator")) return SomeModeratorData(); if(user.HasRole("User")) return SomeData(); return SomeAnonimousData(); потому что тут сложно зацепиться глазами за блоки. Кстати, как вариант, тут может быть if(user.HasRole("Admin")) return SomeAdminData(); if(user.HasRole("Moderator")) return SomeModeratorData(); if(user.HasRole("User")) return SomeData(); /*Anonimous*/ return SomeAnonimousData(); Но с этим подходом надо быть осторожным и использовать только тогда, когда это имеет смысл. Кстати, с этим вариантом могут быть проблемы с автоформатированием в IDE. Потому что я бы однозначно не хотел увидеть if(user.HasRole("Admin")) return SomeAdminData(); if(user.HasRole("Moderator")) return SomeModeratorData(); if(user.HasRole("User")) return SomeData(); /*Anonimous*/ return SomeAnonimousData(); такой вариант вообще нечитаемый. Так же лично я не понимаю зачем открытие скобки писать на новой строке Скобки на новой строке удобны тем, что видно, к какому блоку они относятся. Следующий код читаем. Он читаем даже если скобки по какой-то причине съедут. for(q=0; q $b) $foo->bar($arg1); else BazClass::bar($arg2, $arg3); Во-первых, если понадобится просматривать структуру кода, то это не слишком удобно читать. В смысле, если ты детально просматриваешь метод и читаешь полностью каждую строку, то всё хорошо. Но если ты просто бегло смотришь код, пытаясь понять, где и что используется, то совмещение условия с вызываемым методом может оказаться неудобным. Во-вторых, здесь нельзя поставить breakpoint на вызов метода. Так что отладке может помешать. Сам использую запись в одну строку только иногда в VB, где есть синтаксис однострочного if. Чем: if ($a === $b) { bar(); } elseif ($a > $b) { $foo->bar($arg1); } else { BazClass::bar($arg2, $arg3); } А вот такой стиль я виду впервые. Видел такое: if ($a === $b) { bar(); } elseif ($a > $b) { $foo->bar($arg1); } else { BazClass::bar($arg2, $arg3); } такое if ($a === $b) { bar(); } elseif ($a > $b) { $foo->bar($arg1); } else { BazClass::bar($arg2, $arg3); } и такое if ($a === $b) { bar(); } elseif ($a > $b) { $foo->bar($arg1); } else { BazClass::bar($arg2, $arg3); } Но вот вариант, когда открывающаяся скобка на отдельной строке, а закрывающаяся перед else - это что-то странное. Тоже не понимаю, зачем.

Ответ 6



Включаем истерику Так же лично я не понимаю зачем открытие скобки писать на новой строке, что бы занять ещё одну лишнюю строку? БОЖЕЧКИ БОЖЕЧКИ ЛИШНЯЯ СТРОКА ЗАЙМЕТСЯ ЭТО ЖЕ ЕЩЕ НЕСКОЛЬКО БАЙТ ПО СЕТИ ПЕРЕДАВАТЬ ПОЖАЛУЙ, НЕ БУДУ СТАВИТЬ ЭТУ СКОБКУ Многие говорят что для читаемости, но любой программист знает о таком написании, зачем же увеличить код? ЛЮБОЙ ПРОГРАММИСТ ЗНАЕТ, ЧТО МОЖНО НАПИСАТЬ КОД В ОДНУ СТРОЧКУ, А ПЕРЕМЕННЫЕ МОГУТ БЫТЬ И В ОДИН СИМВОЛ if($a===$b)bar();elseif($a>$b)$f->b($arg1);else Bz::br($a2,$3); МММММ КАКАЯ ВКУСНАЯ ЭКОНОМИЯ БАЙТОВ Если серьезно, то разве вы хоть что-то делаете лучше, избавляясь от лишних пробелов и скобок? Вы же вообще ничего не экономите, ну совсем ничего. Про страшилки и общепринятый PSR уже рассказали.

Ответ 7



Ну и в завершение нашего цирка, вот вам на ночь очень мудрый пример обращения со скобками. Когда этот код был Явой. доказательство public class Permuter { private static void permute(int n, char[] a) { if (n == 0) { System.out.println(String.valueOf(a)) ;} else { for (int i = 0; i <= n; i++) { permute(n-1, a) ; swap(a, n % 2 == 0 ? i : 0, n) ;}}} private static void swap(char[] a, int i, int j) { char saved = a[i] ; a[i] = a[j] ; a[j] = saved ;}}

Ответ 8



Немного опоздал на вечеринку, но все равно зайду. ТС смотри глубже, зачем вообще нужны if, else, эти дурацкие переводы строк, точки с запятой фигурные скобки и знаки доллара если есть старый добрый тренарный условный оператор. (a==b) ? c() : (a>b) ? d.c(f) : e.c(g,h);

Ответ 9



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

Ответ 10



Есть такие программисты-зануды, которые пользуются отладкой кода в ide. И если Вы хотите чтобы они каждый раз, когда захотят поставить точку остановы, вспоминали Вас, то пишите в одну строчку и икота с красными ушами Вам обеспечена!

Ответ 11



Если вам не нравятся скобки, возможно вам стоит выбрать в качестве языка Python. Там с вами полностью солидарны :) if a == b: print('a == b') elif c == d: print('c == d') else print(':)')

Ответ 12



Зачем тут писать скобки? На этот вопрос уже дан хороший ответ. Так же лично я не понимаю зачем открытие скобки писать на новой строке, что бы занять ещё одну лишнюю строку? Зачем писать открытие скобки на новой строке? Сейчас я пишу открытие скобки на новой строке, потому что это соответствует выбранному на данный момент стилю написания и, следовательно, повышает читабельность кода. Тема о преимуществах и недостатках тех или иных стилей слишком обширна и спорна, чтобы затрагивать ее здесь. Зачем писать открытие скобки на той же строке? Долгое время я писал открытие скобки на той же строке, потому что так безопаснее. Приходится иногда видеть такие ошибки (и сам я грешен был): if(1>2); { test = true; } Заканчивать строку точкой с запятой настолько естественно в C/C++, что иногда это делается на бессознательном уровне. Однако, если ставить открытие скобки на новой строке, то появляются строки, которые нельзя закрывать точкой с запятой, потому что это может привести к трудно отлавливаемой логической ошибке. Чтобы такие строки не появлялись, лучше писать так: if(1>2) {; test = true; } Тогда даже лишняя точка с запятой не приведет к ошибке. Да она скорее всего даже не появится, потому что после открывающей скобки бессознательного желания ставить точку с запятой нет. По крайней мере мне такой код видеть не приходилось. P.S. Те, кто не брезгует макросами, могут сочетать открытие скобки на новой строке и безопасность. Например так: #define FOR_S( ... ) for( __VA_ARGS__ ) { #define END_FOR_S } #define IF_S( ... ) if( __VA_ARGS__ ) { #define END_IF_S } #define ELSE_S } else { #define ELSE_IF_S } else IF_S #define WHILE_S( ... ) while( __VA_ARGS__ ) { #define END_WHILE_S } Тогда код с макросами будет выглядеть так: IF_S( toWorkWithA ); { makeAInput(); sendtoA(); } END_IF_S; Лишняя точка с запятой не приведет к ошибке. Однако: а) использование макросов тоже не безопасно, б) для кого-то замена ключевых слов на макросы может влиять на читабельность кода в худшую сторону.

понедельник, 25 ноября 2019 г.

Что есть в Java, чего нет в C#?


Решил попробовать писать под андроид и столкнулся с необходимостью писать на Java
До этого писал больше на C#. Языки похожие во многом, но есть и отличия. И так как пок
я C# знаю лучше Java, то так получается, что я пользуюсь только теми возможностями синтаксиса Java, которые знаю по C#. В общем, сейчас для меня java превратился в "урезаный C#", потому что каких-то чисто джавовских "фишек" я не знаю, а некоторых возможностей из C# в этом языке нет. Ну, например, в Java нет оператора ??, нет linq, нет свойств, нет атрибутов.

Так вот сам вопрос: а что есть в Java, чего нет в C#? Именно из синтаксиса, различных удобностей и синтаксического сахара.
    


Ответы

Ответ 1



Смотрите. В основном по фичам в данный момент C# идёт впереди Java, Java находится в позици догоняющего. Однако есть несколько фич, которые есть в Java и нет в C# и которые при правильном использовании могут облегчить жизнь программисту. 1) Легковесные (анонимные) производные классы. Пример: new Thread(new Runnable() { // это анонимный производный класс! @override public void run() { // do some work } }).start(); В C# надо было бы объявить производный класс явно. Аналогичная, но не равносильная фича C# — анонимные методы, то есть лямбды. 2) Нестатические внутренние классы. В C# внутренние классы лишь логически находятс «внутри» и не имеют доступа к instance-переменным. В Java внутренние классы более богаты. 3) enum'ы. В C# они такие же, как в C++, и являются по существу именованными константам целочисленного типа. В Java enum'ы есть константы объектного типа, гораздо более богатые семантически. 4) checked exceptions. Вы можете объявлять как часть сигнатуры метода исключения которые бросаются этим методом. В C# такой возможности нету. (Хотя разработчики C# считают, что эта фича не нужна и даже вредна, тем не менее по факту это фича, которая есть в Java и нет в C#.) 5) final-параметры. В C# const могут лишь переменные и поля, в Java можно параметр объявить как final, и при попытке его изменить компилятор наругается на вас. 6) SoftReference представляет собой «более сильную» версию WeakReference (которы тоже есть в Java): объекты, референсируемые ими, не удаляются, пока памяти хватает, даже если другие объекты уничтожаются в процессе сборки мусора. 7) У Java есть симпатичные помеченные блоки, которые позволяют выйти из любого количеств циклов за раз (break) или пропустить итерацию во внешнем цикле (continue). Также break

суббота, 15 июня 2019 г.

Что делает синтаксис (type*)?

uchar* ptr = (uchar*) (img->imageData + y * img->widthStep);
А именно: = (type*) (...);


Ответ

Приведение к типу указатель на type. В старом, C-шном стиле.

суббота, 23 марта 2019 г.

Разница между define и const [дубликат]

На данный вопрос уже ответили: Различие define и const 2 ответа В чем в C++ разница между #define и const? То есть какой из вариантов предпочтительнее и в какой ситуации, есть ли вообще разница?


Ответ

#define - это макрос препроцессора, он просто выполняет замену строки текста на своё содержимой. До c++11 его имело смысл использовать для глобальных численных констант.
const - это квалификатор типа, говорящий, что переменная не должна меняться после инициализации. Но эта инициализация где-то должна произойти, и от константности можно вручную избавиться при помощи const_cast.
В c++11 был добавлен квалификатор constexpr, который указывает на то, что переменная может как-то изменяться только во время компиляции, но не во время выполнения. Детали зависят от версии стандарта. Теперь можно без проблем объявлять статические константы, в том числе сложных типов. Например:
namespace constants{ static constexpr double g = 9.8;
struct minus_fn_impl{ template T operator () (const T& lha, const T& rha){ return lha - rha; } };
static constexpr minus_fn_impl minus_fn; }
...
double v = 5.3; double r = constants::minus_fn(v, constants::g); // не нужно инициализировать функциональный объект, как в случае std::minus

среда, 27 февраля 2019 г.

неименованное объединение в структуре

Подсмотрела у коллег в проекте примерно вот такую конструкцию:
struct A { int i; union { char j; double k; }; } a; ... a.j = 'a';
Проект на С, компилируется под gcc. Нашла описание подобного использования union для плюсов, но вот для С такого (использование объединения без имени с упрощенным доступом к его полям) мне раньше не попадалось.
Это допустимая для С конструкция, или это одна из особенностей gcc? При переходе на другой компиллятор с ней проблем не возникнет?


Ответ

Это вполне совместимая со стандартом C, начиная с C11, конструкция. MSVC, который достаточно слабо поддерживает стандарт C, её тем не менее прекрасно понимает.
В стандарте C99 этой конструкции не было, но gcc тем не менее поддерживал её как расширение языка.
Википедия
The standard includes several changes to the C99 language and library specifications, such as: Anonymous structures and unions, useful when unions and structures are nested, e.g. in struct T { int tag; union { float x; int n; }; };
Ссылка на стандарт, §6.7.2.1/13:
An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure; an unnamed member whose type specifier is a union specifier with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.

вторник, 5 февраля 2019 г.

Синтаксис перегрузки операторов C#

Подскажите, пожалуйста, почему метод перегружающий оператор должен быть обязательно public и static?


Ответ

Давайте создадим тестовый класс и перегрузим оператор сложения для него:
public class MyClass { public int A { get; set; }
public static MyClass operator +(MyClass A, MyClass B) { return new MyClass { A = A.A + B.A }; } }
А теперь посмотрим, какие методы декларирует наш класс:
MethodInfo[] methods = typeof(MyClass).GetMethods();
Среди прочего в массиве methods мы увидим такую запись:
MyClass op_Addition(MyClass, MyClass)
Условно, когда вы перегружаете оператор, создается метод с указанным названием и атрибутами Public | Static | HideBySig | SpecialName. Так что следующий код:
MyClass a = new MyClass { A = 1 }; MyClass b = new MyClass { A = 2 }; MyClass c = a + b;
На деле преобразуется в:
MyClass a = new MyClass { A = 1 }; MyClass b = new MyClass { A = 2 }; MyClass c = MyClass.op_Addition(a, b);
Как видите, когда Вы описали оператор, Вы создали статическую функцию с именем op_Addition. Статическая она по той причине, что в C# не предусмотрен вариант типа
public MyClass operator +(MyClass B) { return new MyClass { A = this.A + B.A }; }
Да и это не нужно, так как статическим вариантом можно покрыть любую свою нужду. Так что плодить какие-то дополнительные методы с теми же возможностями - бессмыленно.Почему синтаксис C# не предусматривает приватные перегруженные операторы? По той же причине, по которой он не поддерживает методы с одинаковыми параметрами, но разными модификаторами доступа: компилятор не сможет понять, какую именно функцию Вы захотите использовать в некотором контексте.

пятница, 14 декабря 2018 г.

Двойные и одинарные кавычки

Не нашёл ответ в инете: почему в Java двойные кавычки используются только для строк , а одинарные только для символов? В чём профит?


Ответ

Профит в том, чтобы чётко различать литералы строк и символов. Если бы и строки, и символы можно было задавать с помощью одного и того же типа кавычек, то пришлось бв проверять, символ ли это, или строка. Иногда это вносило бы путаницу, а иногда точно определить это не представлялось бы возможным. Вот пример: public void doSth(String s) {}
public void doSth(char c) {}
doSth("a"); Если бы литералы символов можно было задавать с помощью двойных кавычек, тут возникла бы неопределённость: какой метод вызывать?