2013-06-19 2 views
3

Я написал этот код и получаю AV в нем.Почему мы не делаем PChar ('*') в Delphi 7?

procedure TForm1.Button1Click(Sender: TObject); 
    Var 
    C : Pchar; 
    s : string; 
begin 
    c:= PChar('*'); 
    s := string(c); // AV here , but code works if i put C:= PChar('**') 
    ShowMessage(c); 
end; 

Я не мог понять, почему. Кто-нибудь знает?

Заранее спасибо.

+0

Пожалуйста, укажите, что вы подразумеваете под «AV» точно –

+1

Ваш код не имеет смысла. Во-первых, он работает. Во-вторых, вам не нужно вводить тип в строку. 's: = c;' отлично работает без него и 'ShowMessage (s);' или 'ShowMessage (c);' оба работают также. –

+1

теперь редактировал код. пожалуйста, посмотрите сейчас –

ответ

2

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

Проблема возникает из разных типов данных.

'*'

является Char, но

'**'

струнный

Это будет прекрасно работать с кодом:

procedure TForm1.Button1Click(Sender: TObject); 
Var 
    C : Pchar; 
    s : string; 
begin 
    c:= PChar(string('*')); 
    s := string(c); // AV here , but code works if i put C:= PChar('**') 
    ShowMessage(c); 
end; 
10

С односимвольным строковым литералом вы производите тип Char, а не string, поэтому это не указатель. Когда вы отбрасываете его обратно, он по-прежнему не является указателем, несмотря на его объявленный тип, поэтому его нельзя преобразовать в строку.

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

Если опустить тип ввергнуть целиком, ваш код будет работать одинаково хорошо для любой длины строки вы хотите:

// All PChar assignments, no casting 
c := ''; 
c := '*'; 
c := '**'; 

Кроме того, приведение обратно к string ненужно, а также. Вы можете напрямую назначить PChar, и компилятор автоматически выполняет преобразование:

s := c; 
+0

Интересно, что где-то задокументирована шизофрения струнных литералов. Я не могу это найти. Похоже, что сумасшедший дизайн для ''a' 'относится к одному типу, а' aa'' относится к другому типу. Мне нравится синтаксис литералов C прямо сейчас. –

+0

@David, лучшее, что я могу найти, это где он говорит: «[символьная строка с одним символом, одно или многобайтная, совместима с любым типом символа] (http://docwiki.embarcadero.com/RADStudio/XE2/en/ Fundamental_Syntactic_Elements # Character_Strings) «. Однако это не так подробно, как хотелось бы. Мне часто нравятся «магические» струнные литералы Delphi. Проблемы обычно возникают только при попытке «помочь» компилятору в тех случаях, когда он никогда не нуждался в помощи, как в этом вопросе. Когда он не знает правильный тип, он выдает сообщение об ошибке. Если он этого не сделал, тогда мы не должны быть литье типов. –

+0

Это смешно. Магический актер, который делает PChar (nil) в указатель на нулевой символ, является мощным. Но дело в том, что они подавляют ошибки. Onus на вас кодер, и у вас больше нет компилятора для проверки. Присвоение символа или строки переменной pchar является ошибкой компилятора. Кастинг прав в одном случае, но не в другом. –

3

В самом деле,

c:= PChar('*'); 

скомпилирован как

mov [c],$0000002a 

, как если бы оно было написано:

c:= PChar(ord('*')); 

С ord('*')=$2a, оказывается, что '*' характер тип- (NativeInt), то это целое число преобразуется в указатель. Поэтому, когда вы пытаетесь получить доступ к содержимому c, вы получаете доступ к адресу памяти $0000002a, что является недопустимым и вызывает нарушение доступа.

При компиляции:

c:= PChar('**'); 

Он формируется как

mov eax,$00548984 
    mov [c],eax 

В этом случае константа # 0 состава текстовый буфер (а не Delphi string) генерируется компилятором в пределах исполняемого файла, а c - по его адресу.

Тот факт, что PChar('*') не ведет себя одинаково, является одной «оптимизацией» типа char, которая может быть преобразована в целое число.
Но я понимаю, что это может ввести в заблуждение.

Если вы хотите просто указатель на один символ «*», то вы можете написать либо:

c:=PChar('*'#0); 
c:=PChar(string('*')); 

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

+1

'c: = '*'' то, что необходимо на самом деле. –

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