我们要做的下一个项目将涉及在URL中嵌入信息。具体来说,我们将构造包含整数代码号的url。我们可以直接在URL中嵌入代码号,但我们将致力于的项目的另一个目标是使URL尽可能短。为了使出现在URL中的数字更短,我们将从通常的十进制整数表示法切换到64进制表示法。这样做的好处是,与通常的以10为基数的表示相比,以64为基数表示大数所需的位数更少。
为了使这一切成为可能,我编写了两个函数,可用于编码以64为基数的无符号整型,并将64为基数的字符串解码回无符号整型。
下面是这两个函数的代码:
const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";无效编码(unsigned int n,char* dest) {dest[6] = '\0';(int k = 5; k > 0; k -) {dest [k] =表(n % 64);N /= 64;} dest[0] = table[n];} unsigned int charToInt(char ch) {if(ch >= 'A' && ch <= 'Z') return (int) (ch-'A');如果(ch > = a & & ch < = ' z ')返回26 + (int) (ch - a);如果(ch > = ' 0 ' & & ch < = ' 9 ')返回52 + (int) (ch - ' 0 ');If (ch == '-') return 62;If (ch == '_') return 63;返回0;} unsigned int decode(char* source) {unsigned int n = charToInt(source[0]);For (int k = 1;k <= 5;k++) {n *= 64;n += charToInt(source[k]);}返回n;}
在64进制编码中,我们用一个字符表示0到63之间的每一个可能的数字。上面代码中的表数组存储了这种编码所需的64个字符。
encode()函数将接受一个无符号整型,并将其编码为6个字符的序列。我们总共需要6个字符,因为unsigned int是32位数据类型。每个64位进制数字携带6位信息,因此我们需要6个6位输入来覆盖整个32位。
同样,decode()函数接受一个指向包含6个字符的数组的指针,并将其转换回单个unsigned int。
因为我可能想在多个项目中使用这些代码,所以我将这些代码打包为C源代码文件和C头文件的组合。源代码文件base64.c包含上面所示的代码。下面是这个头文件,base64.h,是为了配合这段代码:
//将一个int类型编码为6个字符void Encode (unsigned int n,char* dest);//将一组6个字符解码为int型unsigned int Decode (char* src);
这个头文件包含源代码文件中定义的两个函数的函数原型。
为了测试这段代码,我还编写了一个简短的测试程序,它包含在一个单独的文件main.c中:
#include <stdio.h> #include "base64.h" int main() {while(1) {printf("(E)ncode, (D) code, or (Q)uit: ");字符缓冲区[16];Unsigned int n;scanf(“% s”,缓冲);if(buffer[0] == 'E' | ' | buffer[0] == 'E') {unsigned long long limit = ((unsigned long long) 2) << 31;printf(“数字必须小于%lld.\n”,limit);printf(“输入一个int: ”);scanf(“% u”,n);编码(n,缓冲);printf (" % s \ n ",缓冲);} else if(缓冲[0]= = ' D ' | |缓冲[0]= = ' D ') {printf("输入代码:");scanf(“% s”,缓冲);N = decode(buffer);printf (" % u \ n, n);} else break;}}
这是我们在本课程中看到的第一个多文件项目。到目前为止,我们一直在使用Visual Studio Code中的构建命令来编译我们的项目。一旦项目超出单个源代码文件,代码中的构建命令就不能正常工作了。对于多文件项目,我们将切换到为项目使用makefile。使用Code中的makefile工具扩展,我们可以轻松地编译、运行和调试多文件项目。
下面是这个项目的makefile:
测试:base64.c main.c
由于项目由两个C源代码文件组成,我们必须在命令行中列出这两个文件以构建项目。因为我们可能还想调试这段代码,所以我在命令行中添加了-g开关。这将编译可执行文件以及调试器所需的调试信息。