Почему std :: cout конвертирует летучие указатели в bool? - PullRequest
16 голосов
/ 23 марта 2010

Если вы попытаетесь установить указатель на тип volatile, даже на переменный указатель типа char, где вы обычно ожидаете, что cout напечатает строку, вместо этого вы просто получите '1' (я думаю, что указатель не нулевой). Я предполагаю, что оператор потока вывода << является шаблоном, специализирующимся на изменчивых указателях, но мой вопрос: почему? Какой вариант использования мотивирует это поведение? </p>

Пример кода:

#include <iostream>
#include <cstring>

int main()
{
    char x[500];
    std::strcpy(x, "Hello world");

    int y;
    int *z = &y;

    std::cout << x << std::endl;
    std::cout << (char volatile*)x << std::endl;

    std::cout << z << std::endl;
    std::cout << (int volatile*)z << std::endl;

    return 0;
}

Выход:

Hello world
1
0x8046b6c
1

Ответы [ 4 ]

27 голосов
/ 23 марта 2010

ostream::operator<< имеет следующие перегрузки, среди прочего:

ostream& operator<< (bool val );
ostream& operator<< (const void* val );

Когда вы передаете энергозависимый указатель, вторая перегрузка не может быть применена, потому что энергозависимые указатели не могут быть преобразованы в энергонезависимые безявное приведение.Однако любой указатель может быть преобразован в bool, поэтому выбирается первая перегрузка, и результат, который вы видите, равен 1 или 0.

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

5 голосов
/ 23 марта 2010

Я думаю, что причина в том, что изменчивые указатели не могут быть неявно преобразованы в void *. Это в Приложении C к Стандарту, и обоснование - безопасность типов.

Изменение: только указатели на неконстантные и энергонезависимые объекты могут быть неявно преобразовано в пустоту * Обоснование: это повышает безопасность типов.

Таким образом, вместо преобразования в void * (который будет печататься в шестнадцатеричном формате), вы получите преобразование по умолчанию в bool.

2 голосов
/ 23 марта 2010

Не ответ

Это просто проблема с формулировкой вопроса и ответов. Проблема возникает из-за невозможности конвертировать указатели в изменчивые объекты в пустые указатели, а не изменчивые указатели .

Разница, которая весьма важна, заключается в том, какой элемент памяти является энергозависимым. В этом вопросе указатель не является энергозависимым (его можно кэшировать, и его не нужно сбрасывать в память при его изменении), а наоборот, указанную память:

int volatile * p = f();
p++;      // this does not affect the perceived state of the c++ memory model
++p;
*p = 5;   // this changes the perceived state

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

void foo( int * );

int * volatile p = f();  // 1
foo(p);                  // 2
int volatile * q = f();
//foo(q);    // error, cannot convert pointer to volatile to pointer to non-volatile
*q = 5;                  // 3
q = 0;                   // 4

В приведенном выше коде операции, помеченные как 1 и 2, полностью перемещаются в память. Назначение в [1] должно быть сохранено в памяти. Даже если значение p находится в регистре, оно будет загружено из памяти в [2]. Операция, помеченная [3], изменяет значение, обозначенное q, которое равно volatile, и будет полностью заполнять основную память, тогда как операция [4] влияет только на указатель, который не является volatile, и это не является частью воспринимаемого состояния модели памяти c ++ и может выполняться в регистрах (обратите внимание, что компилятор может оптимизировать q и выполнять операции в регистре, тогда как p не может быть оптимизирован.

1 голос
/ 23 марта 2010

Я думаю, что проблема не в явной перегрузке для указателей на изменчивые типы, а в НЕДОСТАТОКЕ перегрузки для указателей на изменчивые типы. Компилятор не может неявно удалить квалификатор volatile из указателей, поэтому он проверяет доступные перегрузки, выбирает версию оператора bool bool и преобразует указатель в volatile в bool.

...