高效c语言1快速入门
Posted pythontesting
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高效c语言1快速入门相关的知识,希望对你有一定的参考价值。
本章将开发你的第一个C语言程序:传统的 "Hello, world!"程序。然后讨论一些编辑器和编译器的选项,并阐述移植性问题。
Hello, world!
#include <stdio.h>
#include <stdlib.h>
int main(void)
puts("Hello, world!");
return EXIT_SUCCESS;
在Linux和其他类似Unix的操作系统上,你可以用cc命令调用系统编译器:
$cc hello.c
$ls
a.out hello.c
$./a.out
Hello, world!
% cc -o hello hello.c
% ./hello
Hello, world!
cc命令有许多标志和编译器选项。例如,-o文件标志让你给可执行文件起名字,而不是a.out。
hello.c程序的前两行使用了#include预处理器指令,它的行为就像你在完全相同的位置用指定文件的内容替换它一样。我们包括<stdio.h>和<stdlib.h>头文件来访问这些头文件中声明的函数,然后我们可以在程序中调用这些函数。puts函数在<stdio.h>中声明,而EXIT_SUCCESS宏在<stdlib.h>中定义。正如文件名所示,<stdio.h>包含了C语言标准I/O函数的声明,而<stdlib.h>则包含了一般实用函数的声明。
C定义了两种可能的执行环境:独立的和托管的。独立环境可能不提供操作系统,通常用于嵌入式编程。这些执行环境提供了一套最小的库函数,程序启动时调用的函数的名称和类型是执行环境定义的。
我们定义main返回int类型的值,并将void放在括号内,表示该函数不接受参数。int类型是有符号的整数类型,可以用来表示正、负整数值以及零。与其他程序性语言类似,C语言程序由可以接受参数和返回值的过程(称为函数)组成。每个函数都可重用,你可以根据需要在程序中频繁调用。在本例中,主函数返回的值表示程序是否成功终止。
puts("Hello, world!")打印出"Hello, world!"。 puts函数是标准库函数,它将字符串参数写入stdout(通常代表控制台或终端窗口),并在输出中附加换行符。如果不需要换行可以使用fputs。
return语句退出程序,向主机环境或调用脚本返回一个整数值。EXIT_SUCCESS是类似对象的宏,通常扩展为0,通常定义为:#define EXIT_SUCCESS 0。
检查函数的返回值
函数通常会返回一个计算结果的值,或者表示函数是否成功完成了它的任务。例如,我们在 "Hello, world!"程序中使用的puts函数需要打印字符串并返回int类型的值。如果发生写入错误,puts函数返回宏EOF的值(负整数);否则,它返回非负的整数值。
尽管对于我们的简单程序来说,puts函数不太可能失败并返回EOF,但这是可能的。因为对puts的调用可能会失败并返回EOF,这意味着你的第一个C程序有bug,或者,可以按以下方法改进。
#include <stdio.h>
#include <stdlib.h>
int main(void)
if (puts("Hello, world!") == EOF)
return EXIT_FAILURE;
// code here never executes
return EXIT_SUCCESS;
// code here never executes
注意(puts("Hello, world!")一定要有括号,否则编译会报错:
c$ cc hello2.c
hello2.c: In function ‘main’:
hello2.c:5:5: error: expected ‘(’ before ‘puts’
5 | if puts("Hello, world!") == EOF
| ^~~~
| (
格式化的输出
puts函数是一种将字符串写入stdout的简单好方法,但最终你会需要使用printf函数来打印格式化的输出--例如,打印字符串以外的参数。printf函数接收定义输出格式的格式化字符串,然后是可变数量的参数,这些参数是你想打印的实际数值。例如,如果你想用printf函数来打印Hello, world!,你可以这样写。
printf("%s\\n", "Hello, world!")。
第一个参数是格式字符串"%s\\n"。%s是转换规范,指示printf函数读取第二个参数(字符串字面)并将其打印到stdout。\\n是一个字母转义序列,用于表示非图形字符,并告诉函数在该字符串后面包括新行。
注意不要将用户提供的数据作为第一个参数的一部分传递给printf函数,因为这样做会导致格式化输出的安全漏洞(Seacord 2013)。
编辑器和集成开发环境
可以使用各种编辑器和集成开发环境来开发你的C语言程序。图1-1显示了最常用的编辑器,根据2018年JetBrains的调查。
对于Microsoft Windows,Microsoft的Visual Studio IDE(https://visualstudio.microsoft.com/)是不错的选择。Visual Studio有三个版本。社区版、专业版和企业版。社区版的优点是免费,而其他版本的功能则需要付费。
对于Linux来说,Vim、Emacs、Visual Studio Code和Eclipse都可选择。Vim是许多开发者和高级用户的首选编辑器。它是一个基于vi编辑器的文本编辑器,由Bill Joy在1970年代为Unix的一个版本编写。它继承了vi的按键绑定,但也增加了原vi所缺少的功能和可扩展性。你可以选择安装Vim插件,如YouCompleteMe(https://github.com/Valloric/YouCompleteMe/)或deoplete(https://github.com/Shougo/deoplete.nvim/),为C语言编程提供本地语义完成。
GNU Emacs是可扩展的、可定制的、免费的文本编辑器。它的核心是Emacs Lisp的解释器,这是一种Lisp编程语言的方言,具有支持文本编辑的扩展功能--尽管我从未发现这是个问题。
Visual Studio Code(VS Code)是精简的代码编辑器,支持开发操作,如调试、任务运行和版本控制。它提供了开发人员所需的工具,以实现快速的代码构建--调试循环。VS Code可以在macOS、Linux和Windows上运行,对私人或商业使用都是免费的。
编译器
现在有很多C语言编译器,他么编译器实现了不同版本的C标准。许多用于嵌入式系统的编译器只支持C89/C90。用于Linux和Windows的流行编译器更努力地支持现代版本的C标准,直到并包括对C2x的支持。
- GNU 编译器集
GNU编译器集合(GCC)包括C、C++和Objective-C以及其他语言的前台(https://gcc.gnu.org/)。GCC的开发在GCC指导委员会的指导下遵循明确的开发计划。
GCC已经被采纳为Linux系统的标准编译器,尽管也有用于微软Windows、macOS和其他平台的版本。在Linux上安装GCC很容易。例如,下面的命令在Ubuntu上安装GCC 8。
$ sudo apt-get install gcc-9
$ gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ sudo dnf install gcc # Fedora
- Clang
另一个流行的编译器是Clang(https://clang.llvm.org/)。在Linux上安装Clang也很容易。例如,下面的命令应该在Ubuntu上安装Clang。
$ sudo apt-get install clang
你可以用下面的命令测试你所使用的Clang的版本。
% clang --version
$ clang --version
clang version 10.0.0-4ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
- 微软Visual Studio
Windows最流行的开发环境是Microsoft Visual Studio,它包括IDE和编译器。它与Visual C++ 2019捆绑在一起,其中包括C和C++编译器。
你可以在项目属性页上为Visual Studio设置选项。在C/C++下的高级选项卡上,确保你通过使用编译为C代码(/TC)选项而不是编译为C++代码(/TP)选项来编译为C代码。默认情况下,当你命名一个以.c为扩展名的文件时,它是用/TC编译的。如果文件被命名为.cpp、.cxx或其他一些扩展名,则用/TP编译。
参考资料
- 本文涉及的python测试开发库 谢谢点赞! https://github.com/china-testing/python_cn_resouce
- python精品书籍下载 https://github.com/china-testing/python_cn_resouce/blob/main/python_good_books.md
- 本书英文原版: Effective C An Introduction to Professional C Programming 2020 a4.5-103--.epub
https://url97.ctfile.com/f/18113597-810419181-1f9306 下载密码 订阅号pythontesting 发送 密码 。
移植性
每个C语言编译器的实现都至少有一点不同。编译器不断发展,因此,例如,像GCC这样的编译器可能提供对C17的完全支持,但正在努力实现对C2x的支持,在这种情况下,它可能有一些C2x的功能实现,但没有其他。因此,编译器支持全部的C标准版本(包括中间的版本)。C语言实现的总体发展是缓慢的,许多编译器明显落后于C标准。
如果为C语言编写的程序只使用标准中规定的语言和库的那些功能,就可以认为是严格符合标准的。这些程序的目的是为了最大限度地提高可移植性。然而,由于实现行为的范围,现实世界中没有一个C语言程序是严格符合要求的,也不会是(可能也不应该是)。相反,C标准允许你编写符合要求的程序,这些程序可能依赖于非可移植的语言和库特性。
通常的做法是为一个参考实现编写代码,或者有时为几个实现编写代码,这取决于你打算在哪个平台上部署你的代码。C标准是确保这些实现不会有太大的差异,并允许你一次针对几个实现,而不必每次都学习一种新的语言。
在C标准文件的附件J中列举了五种可移植性问题。
-
实现定义的行为
-
未指定的行为
-
未定义的行为
-
针对本地的行为
-
常见的扩展
-
实现定义的行为
实现定义的行为是指C语言标准中没有规定的程序行为,它可能在不同的实现中提供不同的结果,但在一个实现中具有一致的、有记录的行为。实现定义的行为的一个例子是一个字节中的位数。
实现定义的行为大多是无害的,但在移植到不同的实现时可能会导致缺陷。在可能的情况下,避免编写依赖于实现定义的行为的代码,这些行为在你可能用来编译你的代码的C实现中是不同的。C标准的附件J.3中列举了实现定义行为的完整列表。你可以通过使用static_assert声明来记录你对这些实现定义的行为的依赖。
- 未指定的行为
未指定的行为是指标准提供了两个或多个选项的程序行为。该标准对在任何情况下选择哪个选项没有要求。每次执行一个给定的表达式可能会有不同的结果,或者产生与之前执行相同表达式不同的值。未指定行为的一个例子是函数参数存储布局,它在同一程序中的不同函数调用中可能会有所不同。避免编写依赖于C标准附件J.1中列举的非指定行为的代码。
-
未定义的行为
未定义的行为是指C标准没有定义的行为,或者说是 "在使用不可移植的或错误的程序结构或错误的数据时,标准没有规定的行为"。未定义行为的例子包括有符号的整数溢出和解读一个无效的指针值。具有未定义行为的代码往往是错误的,但比这更有细微差别。标准中对未定义行为的识别如下。 -
当违反了 "应当 "或 "不应当 "的要求,并且该要求出现在约束条件之外时,该行为是未定义的
-
当行为被明确规定为 "未定义行为 "时
-
通过省略任何明确的行为定义
前两种未定义行为经常被称为显式未定义行为,而第三种则被称为隐式未定义行为。这三者之间的重点没有区别,它们都描述了未定义的行为。C语言标准附件J.2 "未定义行为 "包含了C语言中显式未定义行为的列表。
开发者经常误认为未定义的行为是C标准中的错误或遗漏,但将行为归为未定义的决定是有意的,也是经过考虑的。C标准委员会将行为归类为未定义的行为是为了做到以下几点。
- 给予实现者许可,使其不去捕捉难以诊断的程序错误
- 避免定义晦涩难懂的案例,使之有利于一种实现策略而不是另一种策略
- 识别可能的符合要求的语言扩展领域,在这些领域中,实现者可以通过提供官方未定义行为的定义来增强语言。
这三个原因实际上是完全不同的,但都被认为是可移植性问题。编译器(实现)有做以下事情的余地。 - 完全忽略未定义的行为,产生不可预测的结果
- 以环境特征的文件方式行事(有或没有发出诊断书)。
- 终止翻译或执行(发出诊断)。
这些选项都不是很好(尤其是第一个),所以最好避免未定义的行为,除非实现指定这些行为的定义是为了让你调用一个语言增强功能。
- 特定于本地的行为和通用扩展
特定于本地的行为取决于每个实现所记录的国籍、文化和语言的本地惯例。通用扩展在许多系统中被广泛使用,但并不能移植到所有的实现中。
小结
在这章中,你学会了如何编写简单的C语言程序,编译它,并运行它。然后,我们看了几个编辑器和交互式开发环境,以及一些编译器,你可以用它们来开发Windows、Linux和macOS系统上的C语言程序。一般来说,你应该使用较新版本的编译器和其他工具,因为它们往往支持C编程语言的较新功能,并提供更好的诊断和优化。如果较新版本的编译器破坏了你现有的代码,或者你正准备部署你的代码,你可能不想使用较新版本的编译器,以避免在你已经测试过的应用程序中引入不必要的变化。在本章的最后,我们讨论了C语言程序的可移植性。
Go语言使用protobuf快速入门
前言
protobuf 即 Protocol Buffers,是一种轻便高效的结构化数据存储格式,与语言、平台无关,可扩展可序列化。
protobuf 性能和效率大幅度优于 JSON、XML 等其他的结构化数据格式。
protobuf 是以二进制方式存储的,占用空间小,但也带来了可读性差的缺点。protobuf 在通信协议和数据存储等领域应用广泛。
Protobuf 在 .proto
定义需要处理的结构化数据,可以通过 protoc
工具,将 .proto
文件转换为 C、C++、Golang、Java、Python 等多种语言的代码,兼容性好,易于使用。
参考文献
本文文章持续更新于:https://github.com/mailjobblog/dev_go/tree/master/220115_protobuf
protobuf3 官方文档:https://link.jianshu.com/?t=https://developers.google.com/protocol-buffers/docs/proto3
Protocol Buffer 编码:https://developers.google.com/protocol-buffers/docs/encoding?hl=zh-cn#packed
proto service grpc 生成插件:https://github.com/protocolbuffers/protobuf/blob/master/docs/third_party.md
本文代码下载:https://github.com/mailjobblog/dev_go/tree/master/220115_protobuf
安装
安装 protoc
从 Protobuf Releases 下载最先版本的发布包安装。
brew intall protoc
安装 protoc-gen-go
我们需要在 Golang 中使用 protobuf,还需要安装 protoc-gen-go,这个工具用来将 .proto 文件转换为 Golang 代码。
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
Tips:
这儿有个小小的坑,github.com/golang/protobuf/protoc-gen-go
和 google.golang.org/protobuf/cmd/protoc-gen-go
是不同的。
区别在于前者是旧版本,后者是google接管后的新版本,他们之间的API是不同的,也就是说用于生成的命令,以及生成的文件都是不一样的。
检查是否安装成功
$ protoc --version
libprotoc 3.19.3
$ protoc-gen-go --version
protoc-gen-go v1.27.1
protobuf生成代码
快速上手
接下来,我们创建一个非常简单的示例,student.proto
syntax = "proto3";
package main;
// this is a comment
message Student
string name = 1;
bool male = 2;
repeated int32 scores = 3;
在当前目录下执行代码生成命令
$ protoc --go_out=. *.proto
$ ls
student.pb.go student.proto
执行此生成命令是将该目录下的所有的 .proto 文件转换为 Go 代码,我们可以看到该目录下多出了一个 Go 文件 student.pb.go
。这个文件内部定义了一个结构体 Student,以及相关的方法:
type Student struct
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Male bool `protobuf:"varint,2,opt,name=male,proto3" json:"male,omitempty"`
Scores []int32 `protobuf:"varint,3,rep,packed,name=scores,proto3" json:"scores,omitempty"`
得到生成的 student.pb.go
文件后,可以在项目代码中直接使用了。
以下是一个例子,即证明被序列化的和反序列化后的实例,包含相同的数据。
func main()
test := &Student
Name: "geektutu",
Male: true,
Scores: []int3298, 85, 88,
data, err := proto.Marshal(test)
if err != nil
log.Fatal("marshaling error: ", err)
newTest := &Student
err = proto.Unmarshal(data, newTest)
if err != nil
log.Fatal("unmarshaling error: ", err)
// Now test and newTest contain the same data.
if test.GetName() != newTest.GetName()
log.Fatalf("data mismatch %q != %q", test.GetName(), newTest.GetName())
枚举(Enumerations)
枚举类型适用于提供一组预定义的值,选择其中一个。例如我们将性别(gender)定义为枚举类型。
message StudentEnum
string name = 1;
enum Gender
FEMALE = 0;
MALE = 1;
Gender gender = 2;
repeated int32 scores = 3;
生成的Go代码主要信息如下:
type StudentEnum_Gender int32
const (
StudentEnum_FEMALE StudentEnum_Gender = 0
StudentEnum_MALE StudentEnum_Gender = 1
)
type StudentEnum struct
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Gender StudentEnum_Gender `protobuf:"varint,2,opt,name=gender,proto3,enum=main.StudentEnum_Gender" json:"gender,omitempty"`
Scores []int32 `protobuf:"varint,3,rep,packed,name=scores,proto3" json:"scores,omitempty"`
枚举类型的第一个选项的标识符必须是0
,这也是枚举类型的默认值。
别名(Alias)
允许为不同的枚举值赋予相同的标识符,称之为别名,需要打开allow_alias选项。
message StudentAlias
enum Status
option allow_alias = true;
UNKOWN = 0;
STARTED = 1;
RUNNING = 1;
生成的Go语言主要代码如下:
type StudentAlias_Status int32
const (
StudentAlias_UNKOWN StudentAlias_Status = 0
StudentAlias_STARTED StudentAlias_Status = 1
StudentAlias_RUNNING StudentAlias_Status = 1
)
使用其他消息类型
Result是另一个消息类型,在 SearchReponse 作为一个消息字段类型使用。
message StudentResponse
repeated Result results = 1;
message Result
string url = 1;
string title = 2;
repeated string snippets = 3;
嵌套写也是支持的:
message Student2Response
message Result2
string url = 1;
string title = 2;
repeated string snippets = 3;
repeated Result2 results2 = 1;
如果定义在其他文件中,可以导入其他消息类型来使用:
import "myproject/other_protos.proto";
任意类型(Any)
在使用 GRPC 时,常规的操作是将 message 定义好后进行数据传输,但总会遇到某些数据结构进行组合的操作,采用默认的定义 message 方式,造成代码量的激增。
为了解决这个问题 protobuf 提供类型 any 解决 GRPC 中泛型的处理方式
message StudentAny
string message = 1;
repeated google.protobuf.Any details = 2;
生成的Go语言主要代码如下:
type StudentAny struct
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
Details []*anypb.Any `protobuf:"bytes,2,rep,name=details,proto3" json:"details,omitempty"`
oneof
如果你的消息中有很多可选字段, 并且同时至多一个字段会被设置, 你可以加强这个行为,使用oneof特性节省内存。
Oneof字段就像可选字段, 除了它们会共享内存, 至多一个字段会被设置。 设置其中一个字段会清除其它字段。
message StudentOneOf
oneof test_oneof
string name = 4;
SubMessage sub_message = 9;
oneof的特性
- 设置oneof会自动清楚其它oneof字段的值. 所以设置多次后,只有最后一次设置的字段有值
- 如果解析器遇到同一个oneof中有多个成员,只有最后一个会被解析成消息
- oneof不支持repeated
map
message StudentMap
map<string, int32> points = 1;
定义服务(Services)
如果消息类型是用来远程通信的(Remote Procedure Call, RPC),可以在 .proto 文件中定义 RPC 服务接口。
例如我们定义了一个名为 SearchService 的 RPC 服务,提供了 Search 接口,入参是 SearchRequest 类型,返回类型是 SearchResponse
service SearchService
rpc Search (SearchRequest) returns (SearchResponse);
官方仓库也提供了一个 插件列表,帮助开发基于 Protocol Buffer 的 RPC 服务。
生成go代码和grpc代码:
# 由proto生成go代码
protoc --go_out=. *.proto
# 由proto生成go的grpc代码
protoc --go-grpc_out=. *.proto
protoc 命令参数
protoc --proto_path=IMPORT_PATH --<lang>_out=DST_DIR path/to/file.proto
–proto_path=IMPORT_PATH: 可以在 .proto 文件中 import 其他的 .proto 文件,proto_path 即用来指定其他 .proto 文件的查找目录。如果没有引入其他的 .proto 文件,该参数可以省略。
–_out=DST_DIR: 指定生成代码的目标文件夹,例如 –go_out=.
即生成 GO 代码在当前文件夹,另外支持 cpp/java/python/ruby/objc/csharp/php 等语言
推荐风格
文件(Files)
- 文件名使用小写下划线的命名风格,例如 lower_snake_case.proto
- 每行不超过 80 字符
- 使用 2 个空格缩进
包(Packages)
- 包名应该和目录结构对应,例如文件在my/package/目录下,包名应为 my.package
消息和字段(Messages & Fields)
- 消息名使用首字母大写驼峰风格(CamelCase),例如message StudentRequest …
- 字段名使用小写下划线的风格,例如 string status_code = 1
- 枚举类型,枚举名使用首字母大写驼峰风格,例如 enum FooBar,枚举值使用全大写下划线隔开的风格(CAPITALS_WITH_UNDERSCORES ),例如 FOO_DEFAULT=1
服务(Services)
- RPC 服务名和方法名,均使用首字母大写驼峰风格,例如service FooService rpc GetSomething()
protobuf文件规范
syntax
protobuf 有2个版本,默认版本是 proto2,如果需要 proto3,则需要在非空非注释第一行使用 syntax = "proto3"
标明版本。
package
package,即包名声明符是可选的,用来防止不同的消息类型有命名冲突。
option go_package
option go_package="./proto/pb;pb";
这部分的内容是关于最后生成的go文件是处在哪个目录哪个包中,./proto/pb
代表在当前目录生成,pb
代表了生成的go文件的包名是 pb。
message
消息类型 使用 message 关键字定义,Student 是类型名,name, male, scores 是该类型的 3 个字段,类型分别为 string, bool 和 []int32。字段可以是标量类型,也可以是合成类型。
相当于Go语言中的 struct 结构体。一个 .proto 文件中可以写多个消息类型,即对应多个结构体(struct)。
修饰符
每个字段的修饰符默认是 singular
,一般省略不写,repeated
表示字段可重复,即用来表示 Go 语言中的切片类型。
标识符
每个字符 = 后面的数字称为标识符,每个字段都需要提供一个唯一的标识符。标识符用来在消息的二进制格式中识别各个字段,一旦使用就不能够再改变,标识符的取值范围为 [1, 2^29 - 1] 。
文件注释
.proto 文件可以写注释,单行注释 //,多行注释 /* … */
标量类型(Scalar)
.proto Type | Notes | C++ Type | Java Type | Python Type[2] | Go Type | Ruby Type | C# Type | PHP Type |
---|---|---|---|---|---|---|---|---|
double | double | double | float | float64 | Float | double | float | |
float | float | float | float | float32 | Float | float | float | |
int32 | 使用变长编码,对于负值的效率很低,如果你的域有可能有负值,请使用sint64替代 | int32 | int | int | int32 | Fixnum 或者 Bignum(根据需要) | int | integer |
uint32 | 使用变长编码 | uint32 | int | int/long | uint32 | Fixnum 或者 Bignum(根据需要) | uint | integer |
uint64 | 使用变长编码 | uint64 | long | int/long | uint64 | Bignum | ulong | integer/string |
sint32 | 使用变长编码,这些编码在负值时比int32高效的多 | int32 | int | int | int32 | Fixnum 或者 Bignum(根据需要) | int | integer |
sint64 | 使用变长编码,有符号的整型值。编码时比通常的int64高效。 | int64 | long | int/long | int64 | Bignum | long | integer/string |
fixed32 | 总是4个字节,如果数值总是比总是比228大的话,这个类型会比uint32高效。 | uint32 | int | int | uint32 | Fixnum 或者 Bignum(根据需要) | uint | integer |
fixed64 | 总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效。 | uint64 | long | int/long | uint64 | Bignum | ulong | integer/string |
sfixed32 | 总是4个字节 | int32 | int | int | int32 | Fixnum 或者 Bignum(根据需要) | int | integer |
sfixed64 | 总是8个字节 | int64 | long | int/long | int64 | Bignum | long | integer/string |
bool | bool | boolean | bool | bool | TrueClass/FalseClass | bool | boolean | |
string | 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。 | string | String | str/unicode | string | String (UTF-8) | string | string |
bytes | 可能包含任意顺序的字节数据。 | string | ByteString | str | []byte | String (ASCII-8BIT) | ByteString | string |
标量类型如果没有被赋值,则不会被序列化,解析时,会赋予默认值
- strings:空字符串
- bytes:空序列
- bools:false
- 数值类型:0
常见问题
go_package报错
Please specify either:
• a "go_package" option in the .proto source file, or
• a "M" argument on the command line.
在go的1.14版本以后,proto文件中不添加go_package 会报错。
解决方法: option go_package = “./”
或者填写自己的包路径也行如option go_package = “http://github.com/package/name”
安装protoc-gen-go报错
can't load package: package google.golang.org/protobuf/cmd/protoc-gen-go: cannot find package "google.golang.org/protobuf/cmd/protoc-gen-go" in any of:
C:\\Go\\src\\google.golang.org\\protobuf\\cmd\\protoc-gen-go (from $GOROOT)
C:\\Users\\peikai\\go\\src\\google.golang.org\\protobuf\\cmd\\protoc-gen-go (from $GOPATH)
解决方法:
先 go get google.golang.org/protobuf/cmd/protoc-gen-go
然后再 install
安装。
以上是关于高效c语言1快速入门的主要内容,如果未能解决你的问题,请参考以下文章