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 lib 中一样。放置一个变量而不是一个常量,我最终会在不保留所有原始语义的情况下移植一个库。这很糟糕,因为我不知道 C++ 库是否与原始 C 库运行得一样好。

我希望这足够清楚。

一个(希望)更好的解释:

我正在学习 AVR 教程中的教程 - [CODE][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函数的第一个参数从 const更改char* pchar*p,再更改const char* pechar* 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?
如果你想要它是 a 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 回答