Можно ли отличить строковой литерал от С-строки?
От: Went  
Дата: 27.07.15 19:33
Оценка: -1
Здравствуйте. Хочется странного.
Можно ли заставить функцию отличить на входе явно записанный строковой литерал от обычной С-строки, полученной, например, из std::string?
Не суть важно — на этапе компиляции или уже в работе, но чтобы вызовы
void main()
{
  f("one");

  // отличались от    
  std::string s = "two";
  f(s.c_str());
}

Вроде бы строковые литералы имеют тип массива, а не указателя на первый символ? Но массив нельзя сделать аргументом функции
Re: Можно ли отличить строковой литерал от С-строки?
От: VladFein США  
Дата: 27.07.15 19:59
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте. Хочется странного.

W>Можно ли заставить функцию отличить на входе явно записанный строковой литерал от обычной С-строки, полученной, например, из std::string?
  Скрытый текст
W>
W>void main()
W>{
W>  f("one");

W>  // отличались от    
W>  std::string s = "two";
W>  f(s.c_str());
W>}
W>

W>Вроде бы строковые литералы имеют тип массива, а не указателя на первый символ?

Строковый литерал имеет тип const char* (указатель на первый символ).

W>Но массив нельзя сделать аргументом функции

Так?
void f(char a[])
{
}


Попробуйте одновременно объявить
void f(char* a)
{
}


Можно сделать так:
void f(char* a)
{
}
void f(const char* a)
{
}

но оба Ваши вызова попадут в функцию с const параметром.
Первую функцию можно вызвать так:
char a[] = "abcde";
f(a);
Re: Можно ли отличить строковой литерал от С-строки?
От: LuciferSaratov Россия  
Дата: 27.07.15 20:00
Оценка: 4 (1)
Здравствуйте, Went, Вы писали:

W>Здравствуйте. Хочется странного.

W>Можно ли заставить функцию отличить на входе явно записанный строковой литерал от обычной С-строки, полученной, например, из std::string?

платформозависимо скорее всего можно: проверять диапазон адресов.
если в секции .rdata/.rodata — то это литерал.
на windows/linux/osx скорее всего заставить работать можно.
Re: Можно ли отличить строковой литерал от С-строки?
От: okman Беларусь https://searchinform.ru/
Дата: 27.07.15 20:02
Оценка: 4 (1)
Здравствуйте, Went, Вы писали:

W>Можно ли заставить функцию отличить на входе явно записанный строковой литерал от обычной С-строки, полученной, например, из std::string?

W>Не суть важно — на этапе компиляции или уже в работе, ...

На правах бреда (очевидно, не портируемого и со сладкими грабельками в травке).
По стандарту, строковые литералы имеют static storage duration, т.е. память под
них выделяется статически. MS VC++, например, размещает такие строки внутри
самого модуля. Зная эту особенность реализации, можно сделать проверку:
if ( (p >= ImageBase) && (p < (ImageBase + ImageSize)) ) {
    printf("'p' is a string literal.\r\n");
} else {
    printf("'p' is not a string literal.\r\n");
}

ImageBase модуля (exe/dll) обычно уже известен (см. параметры WinMain/DllMain), а
ImageSize можно получить с помощью GetModuleInformation.

  Скрытый текст
Думал минут 5, стоит или нет постить такой бред
Re: Можно ли отличить строковой литерал от С-строки?
От: VTT http://vtt.to
Дата: 27.07.15 20:06
Оценка: 19 (3) +2
Здравствуйте, Went, Вы писали:

W>Здравствуйте. Хочется странного.

W>Можно ли заставить функцию отличить на входе явно записанный строковой литерал от обычной С-строки, полученной, например, из std::string?
W>Не суть важно — на этапе компиляции или уже в работе, но чтобы вызовы
W>
void main()
{
  f("one");

  // отличались от    
  std::string s = "two";
  f(s.c_str());
}

W>Вроде бы строковые литералы имеют тип массива, а не указателя на первый символ? Но массив нельзя сделать аргументом функции

template<size_t symbols_count> auto
foo(const char (& sz_text)[symbols_count]) -> void { ::std::cout << 0; }

template<typename tp_Char> auto
foo(tp_Char const * & psz_text) -> void { ::std::cout << 1; }

template<typename tp_Char> auto
foo(tp_Char const * && psz_text) -> void { ::std::cout << 2; }

foo("qqq"); // вызовет (0)
const char sz_text[]("www");
foo(sz_text); // вызовет (0)
char const * psz_text("eee");
foo(psz_text); // вызовет (1)
::std::string text("rrr");
foo(text.c_str()); // // вызовет (2)
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Отредактировано 27.07.2015 20:35 VTT . Предыдущая версия . Еще …
Отредактировано 27.07.2015 20:14 VTT . Предыдущая версия .
Re[2]: Можно ли отличить строковой литерал от С-строки?
От: Went  
Дата: 27.07.15 20:13
Оценка:
Здравствуйте, VladFein, Вы писали:

VF>Так?

VF>
void f(char a[])
VF>{
VF>}

VF>Попробуйте одновременно объявить
void f(char* a)
VF>{
VF>}

Получим "уже определено".

VF>Можно сделать так:

VF>
VF>void f(char* a)
VF>{
VF>}
VF>void f(const char* a)
VF>{
VF>}
VF>

VF>но оба Ваши вызова попадут в функцию с const параметром.
Ну, само собой.

VF>Первую функцию можно вызвать так:

VF>
VF>char a[] = "abcde";
VF>f(a);
VF>

Ну, само собой.
Re[2]: Можно ли отличить строковой литерал от С-строки?
От: Went  
Дата: 27.07.15 20:17
Оценка:
Здравствуйте, okman, Вы писали:

O>По стандарту, строковые литералы имеют static storage duration, т.е. память под

O>них выделяется статически. MS VC++, например, размещает такие строки внутри
O>самого модуля. Зная эту особенность реализации, можно сделать проверку...

Да, это самый очевидный вариант. Если компилятор различить не может, то только так. А можно еще попытаться туда что-то записать, и если Access Violation, то это статика
Re[2]: Можно ли отличить строковой литерал от С-строки?
От: okman Беларусь https://searchinform.ru/
Дата: 27.07.15 20:18
Оценка: +1
Здравствуйте, VTT, Вы писали:

VTT>
VTT>template<size_t symbols_count> auto
VTT>foo(const char (& sz_text)[symbols_count]) -> void {} // (0)

VTT>auto
VTT>foo(char const * & psz_text) -> void {} // (1)

VTT>auto
VTT>foo(char const * && psz_text) -> void {} // (2)

VTT>foo("qqq"); // вызовет (0)
VTT>const char sz_text[]("www");
VTT>foo(sz_text); // вызовет (0)
VTT>char const * psz_text("eee");
VTT>foo(psz_text); // вызовет (1)
VTT>::std::string text("rrr");
VTT>foo(text.c_str()); // // вызовет (2)
VTT>


А можно для простых смертных описать в двух словах, за счет чего это работает ?
И работает ли (C++14 на ideone.com вместо "0012" выдал "2212": https://ideone.com/CxhHRf) ?
Re[2]: Можно ли отличить строковой литерал от С-строки?
От: Went  
Дата: 27.07.15 20:24
Оценка:
Здравствуйте, VTT.
О, тема Я как раз думал в таком направлении, но не догадался, что можно убрать очевидную перегрузку на const char*, в которую мирно сливались все варианты.
Re[3]: Можно ли отличить строковой литерал от С-строки?
От: VTT http://vtt.to
Дата: 27.07.15 20:33
Оценка: 14 (1)
Здравствуйте, okman, Вы писали:

O>А можно для простых смертных описать в двух словах, за счет чего это работает ?

O>И работает ли (C++14 на ideone.com вместо "0012" выдал "2212": https://ideone.com/CxhHRf) ?

Тогда так
template<size_t symbols_count> auto
foo(const char (& sz_text)[symbols_count]) -> void { ::std::cout << 0; }

template<typename tp_Char> auto
foo(tp_Char const * & psz_text) -> void { ::std::cout << 1; }

template<typename tp_Char> auto
foo(tp_Char const * && psz_text) -> void { ::std::cout << 2; }

Это обеспечит правильный выбор шаблона функции. https://ideone.com/a0s6u8
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Отредактировано 27.07.2015 20:34 VTT . Предыдущая версия .
Re: Можно ли отличить строковой литерал от С-строки?
От: ELazin http://rsdn.ru/forum/prj/6225353.1
Автор: ELazin
Дата: 26.10.15
Дата: 28.07.15 11:35
Оценка: 4 (1)
W>Можно ли заставить функцию отличить на входе явно записанный строковой литерал от обычной С-строки, полученной, например, из std::string?

Не совсем ответ на вопрос, но можно с помощью макросов добиться того, чтобы в функцию нельзя было передать динамическую строку:

#define foo(x) foo_impl(x"")

void foo_impl(const char* x) {
    ...
}


конкатенация будет работать только для статических строк, в противном случае — ошибка компиляции
Re[2]: Можно ли отличить строковой литерал от С-строки?
От: Lorenzo_LAMAS  
Дата: 28.07.15 11:58
Оценка:
VTT>
VTT>template<size_t symbols_count> auto
VTT>foo(const char (& sz_text)[symbols_count]) -> void { ::std::cout << 0; }
VTT>


offtopic
забавно, вы тип функции (auto ... ->void) всегда так записываете?
это врагам назло? или кодинг-стайл такой ... врагам назло?
Of course, the code must be complete enough to compile and link.
Re[3]: Можно ли отличить строковой литерал от С-строки?
От: VTT http://vtt.to
Дата: 28.07.15 13:10
Оценка: +1 -1
Здравствуйте, Lorenzo_LAMAS, Вы писали:

VTT>>
VTT>>template<size_t symbols_count> auto
VTT>>foo(const char (& sz_text)[symbols_count]) -> void { ::std::cout << 0; }
VTT>>


L_L>offtopic

L_L>забавно, вы тип функции (auto ... ->void) всегда так записываете?
L_L>это врагам назло? или кодинг-стайл такой ... врагам назло?

обычный добротный код на C++11, готовый к переводу в ближайшем будущем на C++14 с его return type deduction
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[4]: Можно ли отличить строковой литерал от С-строки?
От: Lorenzo_LAMAS  
Дата: 28.07.15 13:15
Оценка:
VTT>обычный добротный код на C++11, готовый к переводу в ближайшем будущем на C++14 с его return type deduction

я знаю, что это за синтаксическая конструкция. меня заинтересовало, пишете ли вы всегда:

auto fun() -> void
{
}


вместо

void fun()
{
}


и будете ли писать

auto fun()
{
}


вместо
void fun()
{
}
Of course, the code must be complete enough to compile and link.
Re[2]: Можно ли отличить строковой литерал от С-строки?
От: VTT http://vtt.to
Дата: 28.07.15 13:44
Оценка: +2
Здравствуйте, ELazin, Вы писали:

W>>Можно ли заставить функцию отличить на входе явно записанный строковой литерал от обычной С-строки, полученной, например, из std::string?


EL>Не совсем ответ на вопрос, но можно с помощью макросов добиться того, чтобы в функцию нельзя было передать динамическую строку:


EL>
EL>#define foo(x) foo_impl(x"")

EL>void foo_impl(const char* x) {
EL>    ...
EL>}
EL>


EL>конкатенация будет работать только для статических строк, в противном случае — ошибка компиляции


для пишущих макросы в нижнем регистре в аду есть отдельный котел,
но с этим кодом проблема еще и в том, что он будет работать не для статических строк, а только для прямо подставленных строковых литералов
auto & sz_text("ooops");
foo(sz_text); // error
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[4]: Можно ли отличить строковой литерал от С-строки?
От: DarkEld3r  
Дата: 28.07.15 13:44
Оценка: :)
Здравствуйте, VTT, Вы писали:

VTT>обычный добротный код на C++11, готовый к переводу в ближайшем будущем на C++14 с его return type deduction

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

Разве удобно использовать "return type deduction" для всех-всех функций?
Re[5]: Можно ли отличить строковой литерал от С-строки?
От: VTT http://vtt.to
Дата: 28.07.15 13:55
Оценка: :)
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>я знаю, что это за синтаксическая конструкция. меня заинтересовало, пишете ли вы всегда:


обычно я пишу
auto // и всякие public, template, inline на первой строке
fun() -> void // вторая начинается с названия метода

и планирую писать
auto
fun()
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[5]: Можно ли отличить строковой литерал от С-строки?
От: VTT http://vtt.to
Дата: 28.07.15 14:12
Оценка: -2
Здравствуйте, DarkEld3r, Вы писали:

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

DE>Разве удобно использовать "return type deduction" для всех-всех функций?

Я пришел к выводу, что лучше давать методам названия, позволяющие сразу понять, возвращают ли они что-то (и что именно) или нет.
например:
вместо int Area() писать auto Get_Area()
вместо int UpdateArea() писать auto Get_UpdatedArea()
вместо interator begin() писать auto Get_BeginIterator()
вместо t_HitTestResult HitTest() писать auto Get_HitTestResult()
вместо bool visible() и void visible(bool new_visible) писать auto Is_Visible() и Set_Visible(bool visible)
Обычно если метод что-то возвращает (т.е. в его задачи входит действие по возвращению результата), то и название получаются типа Get_Something, Is_Something, Make_Something и т.п.

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

Мне кажется, что автоматический вывод типа возвращаемого значения очень похож на добавленный в C++11 вывод типа переменной в плане применимости и полезности.
Сейчас переменный по большей части объявляются с auto, и так же с методами будет.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Отредактировано 28.07.2015 14:20 VTT . Предыдущая версия .
Re[6]: Можно ли отличить строковой литерал от С-строки?
От: DarkEld3r  
Дата: 28.07.15 14:18
Оценка:
Здравствуйте, VTT, Вы писали:

VTT>Я пришел к выводу, что лучше давать методам названия, дающие ясно понять, возвращают ли они что-то (и что именно) или нет.

Так же делаю.
И у нас auto для переменных в соглашениях прописано и на ревью на это указывают, если вдруг кто забыл. Но вот auto в качестве возвращаемого значения... Может, конечно, это просто консервативность.
Re[3]: Можно ли отличить строковой литерал от С-строки?
От: ELazin http://rsdn.ru/forum/prj/6225353.1
Автор: ELazin
Дата: 26.10.15
Дата: 28.07.15 14:32
Оценка: -1
VTT>для пишущих макросы в нижнем регистре в аду есть отдельный котел,

как пьяный до березы..
а) это всего навсего пример б) есть огромное количество примеров обратного в стандартной библиотеке и не только (в той же APR)

VTT>но с этим кодом проблема еще и в том, что он будет работать не для статических строк, а только для прямо подставленных строковых литералов


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