Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #30 : 10-08-2007 11:37 » |
|
Scorp__), примени MessageBoxEx
|
|
|
Записан
|
|
|
|
Scorp__)
Молодой специалист
Offline
Пол:
|
|
« Ответ #31 : 10-08-2007 15:15 » |
|
Алексей1153++, да решение-то я нашел и описал в своем посте Но вот странное предложение для того чтобы отвязаться от применения одной АПИ функции применить другую? Дело в том, что в .NET MessageBox - это класс такой, а всякий кто хочет показать окошечко с сообщением вызывает статический метод этого класса, Show, с нужным набором параметров. Так вот макрос обитающий в windows.h перекрыл название этого класса в namespace System::Windows::Forms. API функции применять, когда находишься в управляемом (managed) контексте, - довольно недешевое удовольствие и делать это надо только в случае, если другого выхода нет
|
|
|
Записан
|
- А Вы сами-то верите в привидения? - Конечно, нет, - ответил лектор и медленно растаял в воздухе.
|
|
|
LifeMaker
Гость
|
|
« Ответ #32 : 01-06-2008 09:32 » |
|
вот как раз макросов типа #define MaxValue 100 - навалом . Но в последнее время стараюсь объявить через enum
а почему так не стоит делать ?
пакость от такого использования: // объявил #define MaxValue 100
int m[MaxValue]; //использовал
//забыл
... //500 строк кода
void func(int MaxValue) //компилятор нас обматюкает, и придётся долго разбираться почему. { //ещё хуже, если этот MaxValue был объявлен в каком-нибудь библиотечном хидере, а создатель функции случайно выбрал такое же имя }
правильная альтернатива: const int MaxValue = 100;
эффект - тот же, безопасность - выше.
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #33 : 01-06-2008 09:58 » |
|
Потому и принято в именах макросов и констант использовать только прописные буквы, чтобы не путать с именами переменных.
Кстати, имена переменных тоже не следует начинать с прописной буквы - так принято начинать имена типов (классов).
Все становится просто и ясно: MAXVALUE - макрос MaxValue - класс maxValue - переменная или ф-ия
|
|
« Последнее редактирование: 01-06-2008 10:05 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #34 : 01-06-2008 09:59 » |
|
LifeMaker, 1) первое. "//забыл" - так не будет , скорее всего, потому что стараюсь не забывать и делать ундефайны 2) //компилятор нас обматюкает, и придётся долго разбираться почему. - компилятор напишет что нибудь вроде "повторный идентификатор" или "неправильное использование константы". А поскольку я помню, что за константа (имена обычно говорящие даю, да начинаются с def_) - жмём F12 (для студии) и летим к определению. Или по памяти находим. 3) const - не всегда можно применить так гибко, как макрос, к сожалению. А так бы я давно отказался от дефайнов
|
|
|
Записан
|
|
|
|
LifeMaker
Гость
|
|
« Ответ #35 : 01-06-2008 10:10 » |
|
А как же быть с системозависимыми? Например MAX_PATH?
по хоршему можно было объявить const int MAX_PATH = <чего-то там>; и был бы тот же эффект, только немного безопаснее. можно было в другой области видимости использовать MAX_PATH по другому. а почему этого не сделали - дык эта константа писалась на языке С ещё в те времена, когда стандарта C++ не было. только и всего. и использование #define в хидерах микрософта для констант объясняется только желанием сохранить совместимость со старыми C компиляторами. зачем программисту, который пишет программу, которая будет компилиться только одним современным хорошим С++ компилятором поступать также? вообще, перед тем как подражать тому стилю, что используют в Microsoft, Borland и т.д., стоит трижды подумать почему они так сделали и подходит ли такая стратегия вам... Теперь про макросы...
...они позоволяют сделать код компактным, а, соответственно, удобочитаемым (легко просматриваемым) в ключевых местах, не загромождая его повторяющимися сложными выражениями.
А вот какой вред от них?
а как насчет такого макроса? #define sq(val) ((val)*(val)) //возведение в квадрат
int a = sq(3); //всё замечательно, раскроется в "int a = ((3)*(3))" int b = sq(sin(a)); //плохо: "int a = ((sin(a))*(sin(a)))" два вызова sin вместо одного, а могла быть очень сложная конструкция int c = sq(db->query("<сложный долгоий запрос>").IntValue()); //думаю понятно, почему плохо int d = sq(object.getValue()); // а если getValue() модифицирует состояние объекта. будет две модификации вместо одной
все проблемы отпадут, если использовать правильную безопасную альтернативу: template<class T> inline T sq(const T& a) { return a*a; }
да, такая запись чуть длиннее, но она безопасна и кроме того, появляется возможность сделать разную реализацию для разных типов. например: template<class T> inline T min(const T& a, const T& b) { return a<b; }
template<const char*> inline const char* min(const char* a, const char* b) { return (strcmp(a,b)<0) ? a : b; }
а вот сможешь ли ты написать макросом такой min, который работает и для строк, и для int, float и т.п.? причем вред от макроса в том, что стоит перед этими шаблонами кому-то написать (в хидере например) макрос #define min(a,b) (a<b?a:b) и весь мой код будет убит. это я о вреде макросов...
|
|
|
Записан
|
|
|
|
LifeMaker
Гость
|
|
« Ответ #36 : 01-06-2008 10:15 » |
|
RXL, Алексей1153++, не спорю, хороший стиль может решать некоторые проблемы, но вы боретесь с искуственными проблемами, зачем? и приведи пример обяъявления константы, где гибкисти const не хватает...
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #37 : 01-06-2008 11:54 » |
|
>>два вызова sin вместо одного это сразу надо учитывать в макросах, это не есть минус. Шаблоны тож не приплетай, речь не о создании универсальных классов примеры, когда константа не катит, не могу сразу вспомнить, просто помню, что были такие ситауции
|
|
|
Записан
|
|
|
|
LifeMaker
Гость
|
|
« Ответ #38 : 01-06-2008 12:12 » |
|
>>два вызова sin вместо одного это сразу надо учитывать в макросах, это не есть минус. Шаблоны тож не приплетай, речь не о создании универсальных классов почему не приплетать шаблоны? это правильная типобезопасная, подчиняющаяся правилам областей видимости замена таким вот макросам. что ты имеешь против шаблонов? и классов никаких я не создавал. я объявил шаблонную функцию, которая заменяет макрос, и избавляет нас от его недостатков
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #39 : 01-06-2008 12:59 » |
|
LifeMaker, я ничего не имею против шаблонов Открою страшную тайну: я никогда не пользовалься шаблонами
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #40 : 01-06-2008 22:12 » |
|
LifeMaker, Есть ряд очень специфичных случаев которые не одойти без макросров (я не смог), один из таких на форуме когда-то обсуждался (мной точно и помоему пушистый с зайцем участвовали), если очень надо ))) могу поискать.
во всем остальном, полностью согласен
Алексей1153++ и RXL, по поводу того, что могут быть проблемы при использовании дефайнов и их объявлении - так это может быть в сторонней библиотеке или этот код содержится в дорабатываемом уже написанном приложении или его просто напишет ваш коллега (допустим стиль написания кода в компании не утвержден)
|
|
|
Записан
|
С уважением Lapulya
|
|
|
LifeMaker
Гость
|
|
« Ответ #41 : 02-06-2008 05:23 » |
|
Есть ряд очень специфичных случаев которые не одойти без макросров (я не смог), один из таких на форуме когда-то обсуждался (мной точно и помоему пушистый с зайцем участвовали), если очень надо ))) могу поискать.
Не спорю, что есть случаи. Первый - строковый литерал, насколько я знаю, константой не объявишь без лишней переменной. придётся писать #define MY_STR "Hello, world!"
и это будет эффективнее чем const char* MY_STR = "Hello, world!";
но проблема эффективности тут немного надуманная, на практике я предпочту второй вариант. Ещё случай. Совсем недавно я на работе писал функцию WRITE_LOG и сделал её макросом по двум причинам. Во-первых, чтобы в RELEASE-версии была возможность #idef-ом отключить логгирование, во вторых, потому что gcc компилятор (мы и его на работе используем) умеет распознавать ошибки типа fprintf(f,"%d","string") и только при подстановке макросом не теряется связь <форматная строка>+<передаваемые параметры>. Случаи действительно специфичные... я собственно почему тут критикую... Алексей1153++ и Джон и другие сторонники дефайна ратуют за типичное использование, именно там где его легко избежать. ни одного действительно необходимого случая они не привели....
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #42 : 02-06-2008 11:35 » |
|
LifeMaker, Случаи действительно специфичные... я собственно почему тут критикую... Алексей1153++ и Джон и другие сторонники дефайна ратуют за типичное использование, именно там где его легко избежать. ни одного действительно необходимого случая они не привели.... Если надо могу привести но проблема эффективности тут немного надуманная, на практике я предпочту второй вариант. Я безусловно предпочту второй вариант, однако повторяю есть случаи когда вариант без дефайна серьезно грамоздкий и не решает задачу в общем виде. Ща найду... ну вот тут, что-то на тему... https://forum.shelek.ru/index.php/topic,4744.msg87889.html#msg87889А вот пример с WRITE_LOG эээ нууу противоречит твоим высказываниям... тут как раз макрос обходится на раз два... причем с возможностью отключением функционала #ifdef
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #43 : 02-06-2008 15:11 » |
|
LifeMaker, умеешь обходиться без дефайна - плюс тебе, я не умею Например те же строки. #define MY_STR "Hello, world!" const char* p="text1"MY_STR"text2";
|
|
|
Записан
|
|
|
|
McZim
|
|
« Ответ #44 : 02-06-2008 17:50 » |
|
а как быть например с: #ifndef SOME_H_INCLUDED #define SOME_H_INCLUDED ... ... ... #endif
|
|
|
Записан
|
The CBO without stats is like a morning without coffee. (c) T.Kyte.
|
|
|
LifeMaker
Гость
|
|
« Ответ #45 : 02-06-2008 17:59 » |
|
А вот пример с WRITE_LOG эээ нууу противоречит твоим высказываниям... тут как раз макрос обходится на раз два... причем с возможностью отключением функционала #ifdef
так что бы не было даже вызова пустой функции + вычисление кучи параметров? тут, опять же, немножко надуманная проблема производительности. и воспользовался я макросом не из-за отключабельности, а из-за того, что не хотел терять warning'ов, ибо реально полезная вещь. несколько раз уберегала от ошибок...
|
|
« Последнее редактирование: 02-06-2008 18:02 от LifeMaker »
|
Записан
|
|
|
|
LifeMaker
Гость
|
|
« Ответ #46 : 02-06-2008 18:08 » |
|
а как быть например с: #ifndef SOME_H_INCLUDED #define SOME_H_INCLUDED ... ... ... #endif
#pragma once и не надо говорить о нестандартности и непортируемости. msvc понимает, с++builder, gcc понимает... меня удивляет, когда люди упорно отказываются от #pragma once предпочитаю эту конструкцию из-за стандартности, да;t tckb точно знают, что программа завязана на текущий компилятор и никогда не будет собираться другим компилятором. я когда то тоже так делал. теперь мне за это стыдно
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #47 : 02-06-2008 18:46 » |
|
LifeMaker, а мне не стыдно, не вижу почему надо использовать прагму... Где хоть один плюс? А минус пусть и надуманный (хотя это очень спорно, но флеймить не хочу) на лицо! так что бы не было даже вызова пустой функции + вычисление кучи параметров? Конечно, вообще ничего вызываться не будет. Запихай вызов между ifdef и endif и все в шоколаде. Если лениво каждый раз писать так много ))) но готов пожертвовать созданием объекта (без мемберов) на стеке, то заказтай в структуру типа так struct LoggerWrapper { LoggerWrapper () { #ifdef DEBUG theLogger.write("nmabssfnmsb nms"); #endif } }; ну или что-то вроде того
|
|
|
Записан
|
С уважением Lapulya
|
|
|
LifeMaker
Гость
|
|
« Ответ #48 : 02-06-2008 20:22 » |
|
LifeMaker, а мне не стыдно, не вижу почему надо использовать прагму... Где хоть один плюс? А минус пусть и надуманный (хотя это очень спорно, но флеймить не хочу) на лицо!
прагма удобнее. простой способ сделать простую вещь. одна строка вместо трёх. не болтается сбивающий с толку #endif в конце файла который сильно оторван от других строк, с которыми он неразрывно связан. и кстати как раз сегодня мне эта конструкция немного нервы попортила. мне понадобилось модифицировать h-файл, написанный не мной. загнал туда определение своего класса. компилятор начал меня материть. посмотрел на #ifndef-#define вроде всё как надо. попробавл и так и эдак. потратил минут 15 (файл входил в precompiled header, каждая попытка скомпилить длилась довольно долго). выяснилось что структура файла такова #ifndef __HEADER_SUPER_MACROS #define __HEADER_SUPER_MACROS //много всяких объявлений #endif #idef _MEGA_PARAMETER1 //много объявлений #else //много объявлений #endif #idef _MEGA_PARAMETER2 //много объявлений #else //много объявлений #endif т.е. не весь хидер оказался обрамлён #ifndef-ом. хотя первоначальный взгляд говорит, что вот, всё хорошо. в начале файла #ifndef-#define, а в конце - #endif, а после внимательного чтения всего (!) хидера, оказывается, что не всё так просто...
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #49 : 02-06-2008 20:29 » |
|
LifeMaker, кстати, в студии есть удобная штука для таких случаев -
#ifndef //{ ...километры ...строк #endif //}
если поставить курсор около фигурной скобки и нажать ctrl+} , то курсор будет перемещён к парной скобке. Если ещё и шифт удержать - всё это выделится
|
|
|
Записан
|
|
|
|
Scorp__)
Молодой специалист
Offline
Пол:
|
|
« Ответ #50 : 02-06-2008 20:31 » |
|
Есть искусственный способ ))
#ifndef __HEADER_SUPER_MACROS #define __HEADER_SUPER_MACROS //... код... #endif // __HEADER_SUPER_MACROS Сразу видно какой #endif, что закрывает.
Между прочим, Саттер и Александреску рекомендуют использовать именно этот вариант защиты от повторного включения, а не прагмы компиляторов )
|
|
|
Записан
|
- А Вы сами-то верите в привидения? - Конечно, нет, - ответил лектор и медленно растаял в воздухе.
|
|
|
LifeMaker
Гость
|
|
« Ответ #51 : 02-06-2008 20:38 » |
|
так что бы не было даже вызова пустой функции + вычисление кучи параметров? Конечно, вообще ничего вызываться не будет. Запихай вызов между ifdef и endif и все в шоколаде. Если лениво каждый раз писать так много ))) но готов пожертвовать созданием объекта (без мемберов) на стеке, то заказтай в структуру типа так struct LoggerWrapper { LoggerWrapper () { #ifdef DEBUG theLogger.write("nmabssfnmsb nms"); #endif } }; ну или что-то вроде того [/quote] дык это же сильно неудобно, при каждом вызове функции обрамлять её #idef'ом. зачем делать 100 раз то, что можно сделать один раз? и всех коллег заставлять? (я ведь не один программист на проекте) и каждый вечер просматривать весь проект, проверять, чтоб никто не забыл #idef поставить. и всё равно забудут где-нить поставить и я не замечу. а про помещение в конструктор... это зачем? это вообще что такое? вызов пустого конструктора - это ничуть не лучше вызова пустой функции. и конструктору ещё параметры надо прикрутить. я ведь каждый раз разное пишу в лог. и параметр у конструктора будет не один. у меня ведь WRITE_LOG форматную строку поддерживает.
|
|
|
Записан
|
|
|
|
LifeMaker
Гость
|
|
« Ответ #52 : 02-06-2008 20:41 » |
|
Есть искусственный способ ))
#ifndef __HEADER_SUPER_MACROS #define __HEADER_SUPER_MACROS //... код... #endif // __HEADER_SUPER_MACROS Сразу видно какой #endif, что закрывает.
Между прочим, Саттер и Александреску рекомендуют использовать именно этот вариант защиты от повторного включения, а не прагмы компиляторов )
конечно, Саттер - глава комитета по стандартизации. кому как не ему защищать стандарт. но я то практик... (прошу заметить, Саттера, лично я, уважаю) поторюсь - автор хидера - не я. и то, что автор воспользовался менее удачной конструкцией чем я вылезло боком мне ps. проект поддерживается только под visual studio. аргументы кроссплатформенности тут не катят
|
|
« Последнее редактирование: 02-06-2008 20:43 от LifeMaker »
|
Записан
|
|
|
|
LifeMaker
Гость
|
|
« Ответ #53 : 02-06-2008 20:46 » |
|
более того, если я буду писать кроссплатформенную библиотеку, я вздохну и напишу #ifndef-#define... или если волею судьбы мне придётся использовать какой-нибудь слишком нестандартный компилятор. но если я знаю, что проект никогда не потребует такого, это глупо
|
|
|
Записан
|
|
|
|
Scorp__)
Молодой специалист
Offline
Пол:
|
|
« Ответ #54 : 03-06-2008 09:25 » |
|
Ну у меня ситуация такая, что я не могу быть уверен, что мне не скажут завтра: "а давай-ка то же самое, но под QNX". То есть любое приложение и библиотека должны быть как можно более дружествены к другим компиляторам и платформам )
|
|
|
Записан
|
- А Вы сами-то верите в привидения? - Конечно, нет, - ответил лектор и медленно растаял в воздухе.
|
|
|
LifeMaker
Гость
|
|
« Ответ #55 : 03-06-2008 16:39 » |
|
Scorp__), Ну у меня ситуация такая, что я не могу быть уверен, что мне не скажут завтра: "а давай-ка то же самое, но под QNX". То есть любое приложение и библиотека должны быть как можно более дружествены к другим компиляторам и платформам )
Ну если ситуация действительно такая, то наверно так правильно. Но что-то мне подсказывает, что чаще всего дела обстоят не так... а что ты пишешь? (если не секрет...)
|
|
|
Записан
|
|
|
|
Scorp__)
Молодой специалист
Offline
Пол:
|
|
« Ответ #56 : 03-06-2008 17:09 » |
|
Блин, даже не знаю как написать ) В основном, это небольшие программки для тестов различных комплексов, для замеров времени выполнения это работа на оборонку и комплексы там сейчас активно переводятся с встраиваемых версий винды на qnx и linux. Но инерция большая, поэтому пока все же пишем под винду. Да и другие заказы, которые делаю... не раз звучало, что потом может быть придется сделать такое же под Linux, правда пока еще не приходилось ))
|
|
|
Записан
|
- А Вы сами-то верите в привидения? - Конечно, нет, - ответил лектор и медленно растаял в воздухе.
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #57 : 04-06-2008 09:57 » |
|
Scorp__), Есть искусственный способ )) #ifndef __HEADER_SUPER_MACROS #define __HEADER_SUPER_MACROS //... код... #endif // __HEADER_SUPER_MACROS Сразу видно какой #endif, что закрывает. Между прочим, Саттер и Александреску рекомендуют использовать именно этот вариант защиты от повторного включения, а не прагмы компиляторов ) Это и имелось ввиду. LifeMaker твой пример с больши хеадером не совсем корректный с ммм практической точкой зрения, если так можно выразиться. Я могу и одну функцию я на 15 старниц написать, а потом попросить кого-то в этом разобраться. Если грамотно писать (это безусловно идеал, но в одной команде он достижим) то классы будут короткие, закрывающий endif содержит комет к чему он относится (я когда еще писал, так у меня просто макрос в студии был, который получал на вход имя неймспейса + класса, а создавал он примерно следующее #ifndef __ИМЯНЕЙМСПЕЙСА_ИМЯКЛАССА_H__ #define __ИМЯНЕЙМСПЕЙСА_ИМЯКЛАССА_H__
namespace ИМЯНЕЙМСПЕЙСА { class ИМЯКЛАССА { public: ИМЯКЛАССА(); ~ИМЯКЛАССА(); }; };
#endif // __ИМЯНЕЙМСПЕЙСА_ИМЯКЛАССА_H__ и вообще не испытывал проблем со временем объявления нового класса, поскольку макрос отрабатывает менее пол секунды) и внутри черезчур много idef (а зачем они? да еще и в таком количестве?)
|
|
|
Записан
|
С уважением Lapulya
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #58 : 04-06-2008 10:13 » |
|
LifeMaker, дык это же сильно неудобно, при каждом вызове функции обрамлять её #idef'ом. зачем делать 100 раз то, что можно сделать один раз? и всех коллег заставлять? (я ведь не один программист на проекте) и каждый вечер просматривать весь проект, проверять, чтоб никто не забыл #idef поставить. и всё равно забудут где-нить поставить и я не замечу. вот для этого и это все обернуто в функцию (точнее конструктор), да ее вызов и создание объекта на стеке надо будет стерпеть (потеря производительности на лицо, но если это не критично). Ну а параметры вычисляй уже внутри ifdef (если это не возможно, то и макрос тебя не спасет от их вычислений) В класс лучше оборачивать чем просто в функцию много потенциальных бонусов при минимуме затрат
|
|
|
Записан
|
С уважением Lapulya
|
|
|
LifeMaker
Гость
|
|
« Ответ #59 : 04-06-2008 19:26 » |
|
LifeMaker твой пример с больши хеадером не совсем корректный с ммм практической точкой зрения, если так можно выразиться. Я могу и одну функцию я на 15 старниц написать, а потом попросить кого-то в этом разобраться. Если грамотно писать (это безусловно идеал, но в одной команде он достижим) то классы будут короткие, закрывающий endif содержит комет к чему он относится ... и внутри черезчур много idef (а зачем они? да еще и в таком количестве?)
ну здесь ситуация такая... хидер на самом деле писался на в нашей команде, это библиотечный хидер, из игрового движка (PopCap framework). Движок кстати, на мой взгляд очень хороший... и то, что там применялась такая конструкция ещё не значит, это кривой код, что писали его неквалифицированные программисты. Такая структура хидера там действительно нужна. Выглядит это так... #ifndef __HEADER_MACROS__ #define __HEADER_MACROS__ // обяъявление классов, которое должно быть только один раз #endif
#ifdef USING_FEATURE_FLAG
#define FEATURE_ONE feature_one_call() #define FEATURE_TWO(params) feature_two_call(params) //...
#else
#define FEATURE_ONE #define FEATURE_TWO(params) //...
#endif
в результате такой структуры можно включать этот хидер в разные файлы, предваряя инклуд макросом USING_FEATURE_FLAG, чтобы включить функциональность, либо не предваряя, чтобы выключить. можно даже в один файл несколько раз инклудить попеременно включая или выключая функционал. хотя я бы реализовал это по другому. вот так... //************************************************************* //header1.h: //************************************************************* #pragma once // обяъявление классов, которое должно быть только один раз
//************************************************************* //header2.h: //************************************************************* #include "header1.h"
#ifdef USING_FEATURE_FLAG
#define FEATURE_ONE feature_one_call() #define FEATURE_TWO(params) feature_two_call(params) //...
#else
#define FEATURE_ONE #define FEATURE_TWO(params) //...
#endif
и ещё header1.h я бы подкинул в pch. и всё было бы здорово...
|
|
|
Записан
|
|
|
|
|