指针C和C++之间的区别

Luk*_*uky 1 c c++ pointers arduino ragel

我注意到以下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);
}
Run Code Online (Sandbox Code Playgroud)

在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;
}
Run Code Online (Sandbox Code Playgroud)

是什么原因?

是否有可能修复C++代码以使其编译(和行为)就像它的C对应物一样?

更好的解释:感谢您的所有答案,但大多数人没有得到我真正的问题所以我会尝试更详细地解释.

我正在使用用C编写的库.标题中的函数原型是这样的:

void parse (const char* p, uint16_t len, uint8_t is_eof);
Run Code Online (Sandbox Code Playgroud)

在这个函数的实现中,碰巧运行代码就好了

char* c = p + 6;
Run Code Online (Sandbox Code Playgroud)

如果我用C编写代码并针对这个库进行编译,一切都很好.

现在我想用C++移植这个库,因为我需要在C++项目中使用它.我通过将函数参数重新定义为变量而不是常量来成功移植库.但由于p指针实际上不需要改变,我宁愿将其定义为常量,就像在原始的C lib中一样.放置变量而不是常量我最终移植了一个库而没有保留所有原始语义.这很糟糕,因为我不知道C++库是否与原始C库一样运行.

我希望这很清楚.

(希望)更好的解释:

我正在按照AVR教程中的教程 - [CODE] [C]使用Ragel灵活/高效地解析字符串,问题与parse_microscript()功能有关.

由于我想Serial.println();在解析器中嵌入Arduino代码(即),我试图用C++宿主语言编译这个Ragel解析器,而不是像教程中提出的那样编译C语言.

首先,我尝试包含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;
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到过,我只好到的第一个参数变化parse_microscript函数从常量char* pchar*p,并const char* pechar* pe.

R. *_*des 8

您可以修复通过使用正确类型的人:

const char* c = p + 6;
Run Code Online (Sandbox Code Playgroud)


P.P*_*.P. 5

这就是为什么您应该将 C 和 C++ 视为单独的语言。

你可以抛弃const

char* c = (char*) p + 6;
Run Code Online (Sandbox Code Playgroud)

但这确实是一种不好的做法。

如果你想改变一个指针为什么把它声明为const?
如果你希望它是 a const,你为什么要抛弃常量?

问以上问题,自己决定。

  • const_cast,但这是一个糟糕的主意,不适用于 OP (4认同)
  • 这**不是** C 和 C++ 之间的区别,只是编译器的区别。两种语言都禁止在没有强制转换的情况下丢弃 `const`。对于违反此类规则,两种语言都要求实现**发出诊断**。两个编译器都这样做了。这样做之后,编译器几乎可以自由地做任何事情。 (2认同)