[英]Pointers difference between C and C++
我注意到以下 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 教程中的教程 - [CODE][C] 使用 Ragel 灵活/高效地解析字符串,问题与parse_microscript()
函数有关。
因为我想在解析器中嵌入 Arduino 代码(即Serial.println();
),所以我尝试用 C++ 宿主语言编译这个 Ragel 解析器,而不是教程中建议的 C。
首先,我尝试在生成的 C 代码中包含Arduino.h
,但 ArduinoIDE无法编译(我相信是因为混合了 C 和 C++ 代码)。
然后我尝试从同一个 Ragel 脚本生成 C++ 代码,但是在编译多个“从‘const char*’到‘char*’的无效转换”错误时,针对生成的代码。
让它在 C++ 中工作的唯一方法是删除所有常量关键字。 这很糟糕,因为我正在更改 C 代码的原始语义,但它有效。
我试图通过提供上述 C 和 C++ 片段来隔离问题,但我可能没有很好地解释这一点。
公认的答案是让 C++ 片段编译的原因,但是当我在 Arduino 代码中尝试这个解决方案时,它不起作用。
我将使用命令ragel -G2 -o microscript.cpp microscript.rl
编译的工作 Ragel 脚本:
#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
,你为什么要抛弃 constness ?
提出以上问题,自己决定。
C++ 是强类型的,C 不是。
在 C++ { 'H'...};
是常量字符数组(即const char *
)。 要初始化变量buffer
,类型需要删除const
位。
由于 C 不是强类型的,它只会发出警告。
恕我直言,C++ 在这方面更胜一筹。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.