2013-08-01 5 views
3

Я читал некоторый код, и я наткнулся на этот пример. Я не понимаю, почему автор использует смещение 1 из обеих переменных в последней строке. На первый взгляд я предполагаю, что это незаконно, потому что это относится к возможно неинициализированной области памяти (и это может вызвать ошибку сегментации). Моя голова говорит мне о неопределенном поведении, но так ли это?Смещение с адреса памяти

static bool lt(wchar_t a, wchar_t b) 
{ 
    const std::collate<wchar_t>& coll = 
     std::use_facet< std::collate<wchar_t> >(std::locale()); 
    return coll.compare(&a, &a+1, &b, &b+1) < 0; 
} 

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

+0

collate :: compare принимает ряд символов. Здесь автор использует один объект как диапазон итераторов. [Это совершенно законно] (http://stackoverflow.com/q/9114657/485561). – Mankarse

+0

@Mankarse Адрес аргумента функции + 1 - не является ли это неправильным указателем? Если a и be были указателями, и это было (a, a + 1, b, b + 1), это было бы справедливо; но это выглядит как неопределенное поведение. Я буду ждать тех, кто прочитал спецификации. – Amarghosh

+1

@Amarghosh: Я * имею * прочитал спецификации. См. Связанный QA. '[expr.add]/4: Для целей этих операторов указатель на объект nonarray ведет себя так же, как указатель на первый элемент массива длиной один с типом объекта в качестве его типа элемента.' – Mankarse

ответ

1

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

Поскольку std::collate<T>::compare использует [низкий, высокий уровень) для двух диапазонов, добавление 1 к адресу параметров просто приведет к остановке сравнения после того, как только a будет сравниваться с b. Не должно быть недопустимых обращений к памяти.

+2

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

+2

@DavidBrown: Это законно. Стандарт явно позволяет программам использовать переменную в виде массива точно одного элемента, и, следовательно, указатель один за пределами переменной гарантированно создаст действительный полузакрытый диапазон –

+0

@ DavidRodríguez, который вам нужно знать! –

0

какая книга вы читаете, плюс это зависит от того, что вы тоже сравниваете!

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

0

Тестирование функции

#include <locale> 

static bool lt(wchar_t a, wchar_t b) 
{ 
    const std::collate<wchar_t>& coll = 
     std::use_facet< std::collate<wchar_t> >(std::locale()); 
    return coll.compare(&a, &a+1, &b, &b+1) < 0; 
} 


int main() { 

    bool b = lt('a', 'b'); 
    return 0; 
} 

Внутри отладчика

Breakpoint 1, main() at test.cpp:13 
13  bool b = lt('a', 'b'); 
(gdb) s 
lt (a=97 L'a', b=98 L'b') at test.cpp:6 
6   std::use_facet< std::collate<wchar_t> >(std::locale()); 
(gdb) p &a 
$1 = 0x7fffffffdddc L"a\001翿\x400885" 
(gdb) p &a+1 
$2 = 0x7fffffffdde0 L"\001翿\x400885" 

Из этого я считаю,

  1. код является законным
  2. но &a + 1 имеет в виду, возможно, неинициализированного памяти

Из того, что GDB возвращается я склонен думать, принимая адрес wchar_t возвращает char* таким образом &a (a является wchar_t) является char* к началу переменной многобайтном что is a и &a+1 возвращает указатель на второй байт. Я прав?

+1

Нет, вы не правы. '& a + 1' дает адрес« один-конец-конец »(обработка« a »как одноэлементного массива). Нецелесообразно разыгрывать «& a + 1». Это используется для обработки 'a' как массива из одного элемента, так что его можно использовать в' compare', который ожидает, что ему будет задан начальный и конечный адрес массива символов. – Mankarse

+1

Вы правы в том, что '& a + 1' может ссылаться на инициализированную память. Но это нормально, так как вызов 'coll :: compare' не читается и не записывается в эту память. Вместо этого он использует указатель, чтобы определить, что он достиг конца последовательности. –

+0

И вы ошибаетесь, полагая, что '& a' является' char * '- это' char_t * '. И '& a + 1' не является вторым байтом многобайтового символа, а адресом« следующего »многобайтового символа. –

Смежные вопросы