Я заметил, что следующий код C выдает «предупреждение: инициализация отбрасывает квалификаторы из целевого типа указателя», но все равно компилируется и ведет себя так, как ожидается (выводит символ W).
#include <stdio.h>
int main(int argc, char *argv[])
{
char buffer[20] = {'H','e','l','l','o',' ','W','o','r','l','d','!','\0'};
const char* p = &buffer[0];
char* c = (p + 6);
printf("%c\n",*c);
}
В C ++ довольно похожий код вообще не компилируется с жалобой на «ошибку: недопустимое преобразование из« const char * »в« char * »»
#include <iostream>
using namespace std;
int main()
{
char buffer[20] = {'H','e','l','l','o',' ','W','o','r','l','d','!','\0'};
const char* p = &buffer[0];
char* c = p + 6;
cout << *c;
cout << endl;
return 0;
}
Какова причина?
Можно ли исправить код C ++, чтобы он компилировался (и вел себя) как его аналог C?
Лучшее объяснение: спасибо за все ваши ответы, но большинство из вас не поняли мою реальную проблему, поэтому я попытаюсь объяснить более подробно.
Я использую библиотеку, написанную на C. Прототип функции в заголовке выглядит примерно так:
void parse (const char* p, uint16_t len, uint8_t is_eof);
Внутри реализации этой функции происходит запуск кода вроде
char* c = p + 6;
Все хорошо, если я напишу свой код на C и скомпилирую с этой библиотекой.
Теперь я хочу портировать эту библиотеку в C ++, так как она мне нужна в проекте C ++. Я успешно перенес библиотеку, переопределив параметр функции как переменную, а не как константу. Но так как p
указатель на самом деле не нужно менять, я бы предпочел определить его как константу, как в оригинальной C lib. Помещая переменную, а не константу, я в конечном итоге портирую библиотеку без сохранения всей оригинальной семантики. Это плохо, так как я не могу знать, работает ли библиотека C ++ так же, как оригинальная библиотека C.
Я надеюсь, что это достаточно ясно.
(Надеюсь) еще лучшее объяснение:
Я следую за учебником в AVR Tutorials — [CODE] [C] Разбор строк гибко и эффективно с помощью Ragel и проблема относительно parse_microscript()
функция.
Так как я хотел бы встроить код Arduino (то есть Serial.println();
) в парсере я пытаюсь скомпилировать этот парсер Ragel на языке хоста C ++, а не на C, как предложено в руководстве.
Во-первых, я пытаюсь включить Arduino.h
в сгенерированном коде C, но Arduino IDE не скомпилируется (я верю из-за смешивания кода на C и C ++).
Затем я попытался сгенерировать код на C ++ из того же сценария Ragel, но при компиляции нескольких ошибок «недопустимое преобразование из« const char * »в« char * »сработал, нацеливаясь на сгенерированный код.
Единственный способ заставить его работать в C ++ состоял в том, чтобы удалить все постоянные ключевые слова. Это плохо, так как я изменяю оригинальную семантику кода C, но это работает.
Я попытался выделить проблему с помощью приведенных выше фрагментов C и C ++, но, вероятно, плохо объяснил суть.
Принятый ответ — это то, что позволяет фрагменту кода C ++ компилироваться, но когда я пробую это решение в коде Arduino, оно не работает.
Я поставил рабочий скрипт Ragel, скомпилированный с помощью команды ragel -G2 -o microscript.cpp microscript.rl
:
#include "qp_port.h"#include "pelican.h"#include "bsp.h"#include "Arduino.h"
static uint16_t currentNumber;
%%{
machine microscript;
action ClearNumber {
currentNumber = 0;
}
action PrintNumber {
Serial.print("parameter: ");
Serial.println(currentNumber);
}
action RecordDigit {
uint8_t digit = (*p) - '0';
currentNumber = (currentNumber * 10) + digit;
}
number = ((digit @RecordDigit)+) > ClearNumber % PrintNumber;
whitespace = space+;
numlist = number (',' number)*;
crlf = '\r\n';
OK = crlf 'OK' crlf;
main := |*
crlf => {Serial.println("crlf");};
OK => {Serial.println("OK detected");};
*|;
}%%
%% Write data;
static uint8_t cs; /* The current parser state */
static char* ts;
static char* te;
static char* act;void init_microscript() {
%% write init;
}
void parse_microscript(char* p, uint16_t len, uint8_t is_eof) {
char* pe = p + len; /* pe points to 1 byte beyond the end of this block of data */
char* eof = is_eof ? pe : ((char*) 0); /* Indicates the end of all data, 0 if not in this block */
%% write exec;
}
Как вы можете видеть, мне пришлось изменить первый параметр parse_microscript
функция от const char* p
в char*p
, а также const char* pe
в char* pe
,
Вы можете исправить и то и другое из них с использованием правильных типов:
const char* c = p + 6;
Вот почему вы должны рассматривать C и C ++ как отдельные языки.
Вы можете отбросить const
:
char* c = (char*) p + 6;
Но это действительно плохая практика
Если вы хотите изменить указатель, зачем объявлять его как const?
Если вы хотите, чтобы это было const
зачем вы хотите выбросить это постоянство?
Задайте вышеуказанные вопросы и решите сами.
C ++ более типизирован, C — нет.
В C ++ { 'H' ...};
является массивом постоянных символов (т.е. const char *
). Инициализировать переменную buffer
тип должен иметь const
немного удален
Поскольку C не является строго типизированным, он просто выдает предупреждение.
ИМХО С ++ лучше в этом отношении.