Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 19.12.2011, 04:31   #31
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,323
По умолчанию

Обнаружил, что компилятор Visual 2008 (в режиме компилирования Си кода) не поддерживает константы:
Код:
// main.c

//#define BUFSIZE 100
const int BUFSIZE = 100;

int main () {
    char buf[BUFSIZE];

    return 0;
}
Цитата:
error C2057: требуется константное выражение

Последний раз редактировалось 8Observer8; 19.12.2011 в 07:40.
8Observer8 вне форума Ответить с цитированием
Старый 19.12.2011, 07:16   #32
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Небольшой экперимент:

//где-то в хэдэре
Цитата:
const char* const myGlobolConst="мама";
//где-то в единице трансляции

Цитата:
void ViewAddr(const char* val){ std::cout << "addr="<< &val<<std::endl; }


int main()
{
cout << "t="<<myGlobolConst<<endl;

ViewAddr("1123"); //Вывод: 0031FC2C
ViewAddr(KOL); //Вывод: 0031FC2C
ViewAddr(myGlobolConst); //Вывод: 0031FC2C
}
Эксперимент наглядно демонстрирует 3 фундаментальных момента:

1. Действительно, константный указатель на константу является альтернативой дефайновой константы. И не требует extern

2. Вот этого многие не понимают: нет никакой разницы между дефайном и обычной константой в том смысле, что в той точке, где эта константа используется - она используется ПО ЗНАЧЕНИЮ. Например, у дефайновой литерной константы адрес можно взять так же просто, как и у любой магической литерной константы. Тип данных дефайновой константы определяется по её значению.

Получается, что #define PARENT "папа" это эквивалент const char parent[]="папа";
После препроцессинга, все функции, выполняющую проверку типа будут считать что PARENT имеет тип данных const char[5];

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



3. Этого я сам не понял: почему то он во всех трех случаях вывел один и тот же адрес. Возможно это связанно с тем, что компилятор чего то там оптимизировал...


ps Как тут теги нормальные ставить? Что бы у кода форматирование не уезжало?

Последний раз редактировалось _Bers; 19.12.2011 в 07:37.
_Bers вне форума Ответить с цитированием
Старый 19.12.2011, 08:19   #33
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Цитата:
ps Как тут теги нормальные ставить? Что бы у кода форматирование не уезжало?
тэг для кода .
Цитата:
Получается, что #define PARENT "папа" это эквивалент const char parent[]="папа";
да, const во многом эквивалент, но он куда безопаснее, причину я уже называл.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 19.12.2011, 08:19   #34
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

В догонку:

Докажем, что любые функции, при проверке типа воспринимают литерный дефайн, как массив фиксированной длины

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

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

То есть, если один тип проходит проверку, а другой - нет. Значит типы данных различны.

Итак, поехали..

где-то в хэдэре
Код:
#define MAMA "мама"
const char* const myGlobolConst="мама"; 
const char parent[]="папа";
где-то в единице трансляции:

Код:
void ViewAddr(const char* val){  std::cout << "addr="<< &val<<std::endl; }
void ViewType(const char* val){  std::cout << "Type="<< typeid(val).name()<<std::endl; }
void Test(const char (&)[5]){  std::cout << "Test пройден!\n"; }


int main()
{
    STD;
    cout << "значение="<<"12345"<<endl;       //вывод: 12345
    cout << "значение="<<myGlobolConst<<endl; //вывод: мама
    cout << "значение="<<parent<<endl;        //вывод: папа
    cout << "значение="<<MAMA<<endl;          //вывод: мама

    ViewAddr("12345");        //Вывод: 0031FC2C
    ViewAddr(MAMA);          //Вывод: 0031FC2C
    ViewAddr(myGlobolConst); //Вывод: 0031FC2C
    ViewAddr(parent);        //Вывод: 0031FC2C

    ViewType("12345");        //Вывод: const char* 
    ViewType(MAMA);           //Вывод: const char* 
    ViewType(myGlobolConst);  //Вывод: const char* 
    ViewType(parent);         //Вывод: const char* 

    Test("12345");       //: error C2664: Test: невозможно преобразовать параметр 1 
                               //из 'const char [6]' в 'const char (&)[5]'

    Test(MAMA);          // вывод: тест пройден!

    Test(myGlobolConst); // : error C2664: Test: невозможно преобразовать параметр 
                                  //1 из 'const char *const ' в 'const char (&)[5]'

    Test(parent);        // вывод: тест пройден!
Эксперимент показал: typeid выполняет неявное преобразование типа "массив" к "указателю", а настоящий тип данных дефайновой константы определяется по её значению, и является массивом фиксированной длины

Последний раз редактировалось _Bers; 19.12.2011 в 08:22.
_Bers вне форума Ответить с цитированием
Старый 19.12.2011, 08:32   #35
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

хватит зацикливаться на типе дефайна.

у него есть недостатки, и от них не уйти.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 19.12.2011, 08:33   #36
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от Пепел Феникса Посмотреть сообщение
во многом эквивалент, но он куда безопаснее, причину я уже называл.
Я просто хотел сказать, что любые магические числа, или литерные константы имеют тип, определённый стандартом языка.

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


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

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


Макросы я всегда использую только локально (внутри единицы трансляции). Ни в каких хэдэрах они не фигурируют.
Они не предназначены для массового пользователя.
И использую я их только с одной целью - улучшить читабельность кода, одновременно сокращая количество писанины.

И желательно, что бы об их существовании вообще никто не знал. Инкапсуляция.

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

За науку вам всем огромный респект. Буду переходить на константы))
Все таки профита у них побольше будит, чем у дефайна

(жаль только студия никак не выделяет цветом глобальные переменные, как дефайны)
_Bers вне форума Ответить с цитированием
Старый 19.12.2011, 14:45   #37
still_alive
Great Code Monkey
Форумчанин
 
Аватар для still_alive
 
Регистрация: 09.08.2007
Сообщений: 533
По умолчанию

Цитата:
Например, у дефайновой литерной константы адрес можно взять так же просто, как и у любой магической литерной константы.
Я имел в виду не строковые константы.
Код:
const int k = 2;
#define K 3
const int* pk = &k;
const int* pK = &K; // fail
Цитата:
3. Этого я сам не понял: почему то он во всех трех случаях вывел один и тот же адрес. Возможно это связанно с тем, что компилятор чего то там оптимизировал...
Вместо &val - static_cast<const void*>(val).

Цитата:
Макросы я всегда использую только локально (внутри единицы трансляции). Ни в каких хэдэрах они не фигурируют.
Они не предназначены для массового пользователя.
И использую я их только с одной целью - улучшить читабельность кода, одновременно сокращая количество писанины.
Есть как минимум еще 2 важные цели, для которых нужен препроцессор: директивы условной компиляции (разные ОС, разные компиляторы и проч), диагностические сообщения (__FILE__, __LINE__, и тд).
still_alive вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
как проще ее написать? 777pro777 Помощь студентам 4 25.10.2011 15:05
Как проще сравнивать даты? silvestr PHP 13 17.04.2011 22:24
может можно сделать проще??? Donatello Общие вопросы C/C++ 6 10.01.2011 19:09
Разворачивающиеся меню. Как проще? Web-Gangsta JavaScript, Ajax 4 05.05.2009 17:46
Можно ли проще сделать задачу на паскале? svobodys Помощь студентам 8 02.12.2008 19:53