2

次の 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 ライブラリのように定数として定義することをお勧めします。定数ではなく変数を配置すると、元のセマンティクスをすべて保持せずにライブラリを移植することになります。C++ ライブラリが元の C ライブラリと同じように動作するかどうかわからないので、これは悪いことです。

これが十分に明確であることを願っています。

(うまくいけば)さらに良い説明:

AVR チュートリアル - [コード][C] Ragel を使用して文字列を柔軟に/効率的に解析するのチュートリアルに従っていますが、問題はparse_microscript()関数に関連しています。

Arduino コード (つまり ) をパーサーに埋め込みたいのでSerial.println();、チュートリアルで提案されている C ではなく、C++ ホスト言語でこの Ragel パーサーをコンパイルしようとしています。

まず、Arduino.h生成された C コードに含めようとしましたが、Arduino IDEはコンパイルされません (C と C++ コードが混在しているためだと思います)。

次に、同じ Ragel スクリプトから C++ コードを生成しようとしましたが、コンパイル時に複数の「'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関数の最初のパラメーターを constchar* pからchar*p、およびconst char* peに変更する必要がありましたchar* pe

4

3 に答える 3

9

正しいタイプを使用して、両方を修正できます。

const char* c = p + 6;
于 2012-12-07T15:26:43.510 に答える
5

そのため、C と C++ を別の言語として扱う必要があります。

次のものをキャストできますconst

char* c = (char*) p + 6;

しかし、これは本当に悪い習慣です。

ポインターを変更したい場合、なぜそれを const として宣言するのでしょうか?
にしたいのならconst、なぜconstnessを捨てたいのですか?

上記の質問をして、自分で決めてください。

于 2012-12-07T15:24:40.990 に答える
3

C++ はより強く型付けされていますが、C はそうではありません。

C++ では{ 'H' ...};、定数文字 (つまりconst char *) の配列です。変数を初期化するには、型からビットを削除bufferする必要があります。const

C は強く型付けされていないため、警告を発行するだけです。

私見 C++ はこの点で優れています。

于 2012-12-07T15:23:32.640 に答える