当前位置: 首页 > news >正文

设置个网站要多少钱找工作哪个网站好58同城

设置个网站要多少钱,找工作哪个网站好58同城,网站建设制作要学什么,南昌网站建设公司市场华为CC语言编程规范 1.基本要求1.1 变量规则1.1.1#xff1a;指针变量、表示资源描述符的变量、BOOL变量声明必须赋予初值规则1.1.2#xff1a;指向资源句柄或描述符的变量#xff0c;在资源释放后立即赋予新值规则1.1.3#xff1a;类的成员变量必须在构造函数中赋予初… 华为CC语言编程规范 1.基本要求1.1 变量规则1.1.1指针变量、表示资源描述符的变量、BOOL变量声明必须赋予初值规则1.1.2指向资源句柄或描述符的变量在资源释放后立即赋予新值规则1.1.3类的成员变量必须在构造函数中赋予初值规则1.1.4严禁对指针变量进行sizeof操作建议1.1.1尽量使用const建议1.1.2全局变量的访问如果涉及多个线程需要考虑多线程竞争条件问题建议1.1.3同一个函数内局部变量所占用的空间不要过大 1.2 断言(ASSERT)规则1.2.1断言必须使用宏定义禁止直接调用系统提供的assert()规则1.2.2运行时可能会导致的错误严禁使用断言建议1.2.1不要将多条语句放在同一个断言中 1.3 函数规则1.3.1数组作为函数参数时必须同时将其长度作为函数的参数规则1.3.3不对内容进行修改的指针型参数定义为const建议1.3.2字符串或指针作为函数参数时请检查参数是否为NULL 1.4 异常机制规则1.4.1禁用C异常机制 1.5 类规则1.5.1构造函数内不能做任何有可能失败的操作规则1.5.2严禁在构造函数中创建线程规则1.5.3如果类的公共接口中返回类的私有数据地址则必须加const类型建议1.5.4尽量避免定义public成员 1.6 安全退出规则1.6.1禁用atexit函数规则1.6.2严禁调用kill、TerminateProcess函数终止其他进程规则1.6.3禁用pthread_exit、ExitThread函数建议1.6.1禁用exit、ExitProcess函数main函数除外建议1.6.2禁用abort函数 2.字符串/数组操作规则2.1确保有足够的存储空间规则2.2对字符串进行存储操作确保字符串有’\0’结束符规则2.3外部数据作为数组索引时必须确保在数组大小范围内规则2.4外部输入作为内存操作相关函数的复制长度时需要校验其合法性规则2.5调用格式化函数时禁止format参数由外部可控 3.整数规则3.1整数之间运算时必须严格检查确保不会出现溢出、反转、除0规则3.2整型表达式比较或赋值为一种更大类型之前必须用这种更大类型对它进行求值规则3.3禁止对有符号整数进行位操作符运算规则3.4禁止整数与指针间的互相转化规则3.5禁止对指针进行逻辑或位运算、||、!、、、、、^、|规则3.6循环次数如果受外部数据控制需要校验其合法性 4.内存规则4.1内存申请前必须对申请内存大小进行合法性校验规则4.2内存分配后必须判断是否成功规则4.3禁止引用未初始化的内存规则4.3禁止引用未初始化的内存规则4.4内存释放之后立即赋予新值规则4.5禁止使用realloc()函数 5.文件输入/输出规则5.1创建文件时必须显式指定合适的文件访问权限 1.基本要求 1.1 变量 规则1.1.1指针变量、表示资源描述符的变量、BOOL变量声明必须赋予初值 变量声明赋予初值可以避免由于编程人员的疏忽导致的变量未初始化引用。 示例 SOCKET s INVALID_SOCKET; unsigned char *msg NULL; BOOL success FALSE; int fd -1;以下代码由于变量声明未赋予初值在最后free的时候出错。 char *message; // 错误必须声明为 char *message NULL;... if (condition) {message (char *)malloc(len);...}... if (message ! NULL) {free(message); //如果condition未满足会造成free未初始化的内存。 }规则1.1.2指向资源句柄或描述符的变量在资源释放后立即赋予新值 资源释放后对应的变量应该立即赋予新值防止后续又被重新引用。如果释放语句刚好在变量作用域的最后一句可以不进行赋值。 示例 SOCKET s INVALID_SOCKET; unsigned char *msg NULL; int fd -1;...closesocket(s);s INVALID_SOCKET;...free(msg);msg (unsigned char *)malloc(...); //msg变量又被赋予新值...close(fd);fd -1;...规则1.1.3类的成员变量必须在构造函数中赋予初值 变量声明赋予初值可以避免由于编程人员的疏忽导致的变量未初始化引用。 示例 class CMsg { public:CMsg();~CMsg();protected:int size;unsigned char *msg; };CMsg::CMsg() {size 0;msg NULL;}规则1.1.4严禁对指针变量进行sizeof操作 编码人员往往由于粗心将指针当做数组进行sizeof操作导致实际的执行结果与预期不符。 下面的代码buffer和path分别是指针和数组编码人员想对这2个内存进行清0操作但由于编码人员的疏忽第5行代码将内存大小误写成了sizeof与预期不符。 char *buffer (char *)malloc(size); char path[MAX_PATH] {0}; ... memset(path, 0, sizeof(path)); memset(buffer, 0, sizeof(buffer));如果要判断当前的指针类型大小请使用sizeof(char *)的方式。 建议1.1.1尽量使用const 在变量声明前加const关键字表示该变量不可被修改这样就可以利用编译器进行类型检查将代码的权限降到更低。 例如下面是不好的定义 float pi 3.14159f;应当这样定义 const float PI 3.14159f;建议1.1.2全局变量的访问如果涉及多个线程需要考虑多线程竞争条件问题 应该尽可能减少全局变量的使用如果多个线程会访问到该全局变量则访问过程必须加锁。 以下代码中g_list是全局变量对链表进行搜索操作时在while循环语句的前后加锁。 ItemList *g_list NULL; ItemList *SearchList(const char *name) {Lock();ItemList *p g_list;while (p ! NULL){if (strcmp(p-name, name) 0){break;}p p-next;}UnLock();return p; }性能敏感的代码请考虑采用原子操作或者无锁算法。 建议1.1.3同一个函数内局部变量所占用的空间不要过大 程序在运行期间函数内的局部变量保存在栈中栈的大小是有限的。如果申请过大的静态数组可能导致出现运行出错。 建议在申请静态数组的时候大小不超过0x1000。 下面的代码buff申请过大导致栈空间不够程序发生stackoverflow异常。 #define MAX_BUFF 0x1000000 int Foo() {char buff[MAX_BUFF] {0};... }1.2 断言(ASSERT) 断言是一种除错机制用于验证代码是否符合编码人员的预期。编码人员在开发期间应该对函数的参数、代码中间执行结果合理地使用断言机制确保程序的缺陷尽量在测试阶段被发现。 断言被触发后说明程序出现了不应该出现的严重错误程序会立即提示错误并终止执行。 断言必须用宏进行定义只在调试版本有效最终发布版本不允许出现assert函数例如 #include assert.h #ifdef DEBUG #define ASSERT(f) assert(f) #else #define ASSERT(f) ((void)0) #endif下面的函数VerifyUser上层调用者会保证传进来的参数是合法的字符串不可能出现传递非法参数的情况。因 此在该函数的开头加上4个ASSERT进行校验。 BOOL VerifyUser(const char *userName, const char *password) {ASSERT(userName ! NULL);ASSERT(strlen(userName) 0);ASSERT(password ! NULL);ASSERT(strlen(password) 0);... }以下的switch由于不可能出现default的情况所以在default处直接调用ASSERT enum {COLOR_RED 1,COLOR_GREEN,COLOR_BLUE }; ... switch (color) {case COLOR_RED:...case COLOR_GREEN:...case COLOR_BLUE:...default: {ASSERT(0);} }以下代码SendMsg是CMsg类的成员函数socketID是成员变量在调用SendMsg的时候必须保证socketID已经 被初始化因此在此处用ASSERT判断socketID的合法性。 CMsg::CMsg() {socketID INVALID_SOCKET; } int CMsg::SendMsg(const char *msg, int len) {ASSERT(socketID ! INVALID_SOCKET);...ret send(socketID, msg, len, 0);... }在linux内核中定义ASSERT宏可以采用如下方式 #ifdef DEBUG #define ASSERT(f) BUG_ON(!(f)) #else #define ASSERT(f) ((void)0) #endif规则1.2.1断言必须使用宏定义禁止直接调用系统提供的assert() 断言只能在调试版使用断言被触发后程序会立即退出因此严禁在正式发布版本使用断言请通过编译选项进行控制。 错误用法如 int Foo(int *array, int size) {assert(array ! NULL);... }规则1.2.2运行时可能会导致的错误严禁使用断言 断言不能用于校验程序在运行期间可能导致的错误。 以下代码的所有ASSERT的用法是错误的。 FILE *fp fopen(path, r); ASSERT(fp ! NULL); //文件有可能打开失败 char *str (char *)malloc(MAX_LINE ASSERT(str ! NULL); //内存有可能分配失败 ReadLine(fp, str); char *p strstr(str, age); ASSERT(p ! NULL); //文件中不一定存在该字符串 int age atoi(p4); ASSERT(age 0); //文件内容不一定符合预期 建议1.2.1不要将多条语句放在同一个断言中 为了更加准确地发现错误的位置每一条断言只校验一个条件。 下面的断言同时校验多个条件在断言触发的时候无法判断到底是哪一个条件导致的错误 int Foo(int *array, int size) {ASSERT(array ! NULL size 0 size MAX_SIZE);... }应该将每个条件分开 int Foo(int *array, int size) {ASSERT(array ! NULL);ASSERT(size 0);ASSERT(size MAX_SIZE);... }1.3 函数 规则1.3.1数组作为函数参数时必须同时将其长度作为函数的参数 通过函数参数传递数组或一块内存进行写操作时函数参数必须同时传递数组元素个数或所传递的内存块大小否则函数在使用数组下标或访问内存偏移时无法判断下标或偏移的合法范围产生越界访问的漏洞。 以下代码中函数ParseMsg不知道msg的范围容易产生内存越界访问漏洞。 int ParseMsg(BYTE *msg) {... } ... size_t len ... BYTE *msg (BYTE *)malloc(len); //此处分配的内存块等同于字节数组 ... ParseMsg(msg); ...正确的做法是将msg的大小作为参数传递到ParseMsg中如下代码 int ParseMsg(BYTE *msg, size_t msgLen) {ASSERT(msg ! NULL);ASSERT(msgLen ! 0);... } ... size_t len ... BYTE *msg (BYTE *)malloc(len); ... ParseMsg(msg, len); ...规则1.3.3不对内容进行修改的指针型参数定义为const 如果参数是指针型参数且内容不会被修改请定义为const类型。 int Foo(const char *filePath) {...int fd open(filePath, ...);... }建议1.3.2字符串或指针作为函数参数时请检查参数是否为NULL 如果字符串或者指针作为函数参数为了防止空指针引用错误在引用前必须确保该参数不为NULL如果上层调用者已经保证了该参数不可能为NULL在调用本函数时在函数开始处可以加ASSERT进行校验。 例如下面的代码因为BYTE *p有可能为NULL,因此在使用前需要进行判断。 int Foo(int *p, int count) {if (p ! NULL count 0){int c p[0];}...int Foo2(){int *arr ...int count ...Foo(arr, count);...} }下面的代码由于p的合法性由调用者保证对于Foo函数不可能出现p为NULL的情况因此加上ASSERT进行校 验。 int Foo(int *p, int count) {ASSERT(p ! NULL); //ASSERT is added to verify p.ASSERT(count 0);int c p[0];... } int Foo2() {int *arr ...int count ......if (arr ! NULL count 0){Foo(arr, count);}... }1.4 异常机制 规则1.4.1禁用C异常机制 严禁使用C的异常机制所有的错误都应该通过错误值在函数之间传递并做相应的判断, 而不应该通过异常机制进行错误处理。 编码人员必须完全掌控整个编码过程建立攻击者思维增强安全编码意识主动把握有可能出错的环节。而使用C异常机制进行错误处理会削弱编码人员的安全意识。 异常机制会打乱程序的正常执行流程使程序结构更加复杂原先申请的资源可能会得不到有效清理。 异常机制导致代码的复用性降低使用了异常机制的代码不能直接给不使用异常机制的代码复用。 异常机制在实现上依赖于编译器、操作系统、处理器使用异常机制导致程序执行性能降低。 在二进制层面程序被加载后异常处理函数增加了程序的被攻击面攻击者可以通过覆盖异常处理函数地址达到攻击的效果。 例外 在接管C语言本身抛出的异常例如new失败、STL、第三方库例如IDL抛出的异常时可以使用异常机制例如 int len ...; char *p NULL; try {p new char[len]; } catch (bad_alloc) {...abort(); }1.5 类 规则1.5.1构造函数内不能做任何有可能失败的操作 构造函数没有返回值不能做错误判断因此在构造函数内不能做任何有可能失败的操作。 下面的代码中 open、new、ConnectServer都有可能失败这些操作不应该放在构造函数内。 CFoo::CFoo() {int fd open(...);char *str new char[...];BOOL b ConnectServer(...);... }规则1.5.2严禁在构造函数中创建线程 构造函数内仅作成员变量的初始化工作其他的操作通过成员函数完成。 规则1.5.3如果类的公共接口中返回类的私有数据地址则必须加const类型 class CMsg { public:CMsg();~CMsg();Const unsigned char *GetMsg(); protected:int size;unsigned char *msg; };CMsg::CMsg() {size 0;msg NULL; } const unsigned char *CMsg::GetMsg() {return msg; }建议1.5.4尽量避免定义public成员 类成员进行定义的时候需要考虑类的功能尽量减少对外接口的暴露。 1.6 安全退出 规则1.6.1禁用atexit函数 atexit函数注册若干个有限的函数当exit被调用后自动调用由atexit事先注册的函数。 当资源不再使用后编码人员应该立即主动地进行清理而不应该在最终程序退出后通过事先注册的例程被动地清理。 例外 作为服务维测监控功能为定位程序异常退出原因的模块可以作为例外使用atexit()函数。 规则1.6.2严禁调用kill、TerminateProcess函数终止其他进程 调用kill、TerminateProcess等函数强行终止其他进程(如kill -9)会导致其他进程的资源得不到清理。 对于进程间通信应该主动发送一个停止命令通知对方进程安全退出。 当发送给对方进程退出信号后在等待一定时间内如果对方进程仍然未退出可以调用kill、TerminateProcess函数。 if (WaitForRemoteProcessExit(...) TIME_OUT) {kill(...); //目标进程在限定时间内仍然未退出强行结束目标进程 }规则1.6.3禁用pthread_exit、ExitThread函数 严禁在线程内主动终止自身线程线程函数在执行完毕后会自动、安全地退出。主动终止自身线程的操作不仅导致代码复用性变差同时容易导致资源泄漏错误。 建议1.6.1禁用exit、ExitProcess函数main函数除外 程序应该安全退出除了main函数以外禁止任何地方调用exit、ExitProcess函数退出进程。直接退出进程会导致代码的复用性降低资源得不到有效地清理。 程序应该通过错误值传递的机制进行错误处理。 以下代码加载文件加载过程中如果出错直接调用exit退出 void LoadFile(const char *filePath) {FILE* fp fopen(filePath, rt);if (fp NULL) {exit(0);}... }正确的做法应该通过错误值传递机制例如 BOOL LoadFile(const char *filePath) {BOOL ret FALSE;FILE* fp fopen(filePath, rt);if (fp ! NULL) {...}...return ret; }建议1.6.2禁用abort函数 abort会导致程序立即退出资源得不到清理。 例外 只有发生致命错误程序无法继续执行的时候在错误处理函数中使用abort退出程序例如 void FatalError(int sig) {abort(); } int main(int argc, char *argv[]) {signal(SIGSEGV, FatalError);... }2.字符串/数组操作 规则2.1确保有足够的存储空间 部分字符串处理函数由于设计时安全考虑不足或者存在一些隐含的目的缓冲区长度要求容易被误用导致缓冲区写溢出。典型函数如itoarealpath。 以下的代码试图将数字转为字符串但是目标存储空间的长度不足。 int num ... char str[8] {0}; itoa(num, str, 10); // 10进制整数的最大存储长度是12个字节 以下的代码试图将路径标准化但是目标存储空间的长度不足。 char resolvedPath[100] {0}; realpath(path, resolvedPath); //realpath函数的存储缓冲区长度是由PATH_MAX常量定义或是由 _PC_PATH_MAX系统值配置的通常都大于100字节以下的代码在对外部数据进行解析并将内容保存到name中考虑了name的大小是正确的做法。 char *msg GetMsg(); ... char name[MAX_NAME] {0}; int i0; //必须考虑msg不包含预期的字符’\n’ while (*msg ! \0 *msg ! \n i sizeof(name) - 1) {name[i] *msg; } name[i] \0; //保证最后有’\0’规则2.2对字符串进行存储操作确保字符串有’\0’结束符 对字符串进行存储操作必须确保字符串有’\0’结束符否则在后续的调用strlen等操作中可能会导致内存越界访问漏洞。 规则2.3外部数据作为数组索引时必须确保在数组大小范围内 外部数据作为数组索引对内存进行访问时必须对数据的大小进行严格的校验否则为导致严重的错误。 下面的代码通过if语句判断offset的合法性 int Foo(BYTE *buffer, int size) {...int offset ReadIntFromMsg();if (offset 0 offset size) {BYTE c buffer[offset];...}... }规则2.4外部输入作为内存操作相关函数的复制长度时需要校验其合法性 在调用内存操作相关的函数时例如memcpy、memmove、memcpy_s、memmove_s等如果复制长度外部可控则必须校验其合法性否则容易导致内存溢出。 下例中循环长度来自设备外部报文由于没有校验大小可造成缓冲区溢出 typedef struct BigIntType {unsigned int length;char val[MAX_INT_DIGITS]; }BigInt;BigInt *AsnOctsToBigInt(const AsnOcts *asnOcts) {BigInt *bigNumber NULL;...for (i 0; i asnOcts-octetLen; i) {bigNumber-val[i] asnOcts-octs[i];}... }规则2.5调用格式化函数时禁止format参数由外部可控 调用格式化函数时如果format参数由外部可控会造成字符串格式化漏洞。 这些格式化函数有 char *msg GetMsg(); ... printf(msg);推荐做法 char *msg GetMsg(); ... printf(%s\n, msg);3.整数 规则3.1整数之间运算时必须严格检查确保不会出现溢出、反转、除0 在计算机中整数存储的长度是固定的例如32位或64位当整数之间进行运算时可能会超过这个最大固定长度导致整数溢出或反转使得实际计算结果与预期结果不符。 如果涉及到除法或者求余操作必须确保除数不为0。 错误示例1 size_t width ReadByte(); size_t height ReadByte(); size_t total width * height; //可能整数溢出 void *bitmaps malloc(total);推荐做法1 size_t width ReadByte(); size_t height ReadByte(); if (width 0 || height 0 || width MAX_WIDTH || height MAX_HEIGHT) { //error... } size_t total width * height; // MAX_WIDTH * MAX_HEIGHT 不会溢出 void *bitmaps malloc(total);错误示例2 size_t a ReadByte(); size_t b 1000 / a; //a可能是0 size_t c 1000 % a; //a可能是0 ...推荐做法2 size_t a ReadByte(); if (a 0) {//error... } size_t b 1000 / a; //a不可能是0 size_t c 1000 % a; //a不可能是0 ...规则3.2整型表达式比较或赋值为一种更大类型之前必须用这种更大类型对它进行求值 由于整数在运算过程中可能溢出当运算结果赋值给比他更大类型或者和比他更大类型进行比较时会导致实际结果与预期结果不符。 请观察以下二个代码及其输出 int main(int argc, char *argv[]) {unsigned int a 0x10000000;unsigned long long b a * 0xab;printf(b %llX\n, b);return 0; }// 输出 b B0000000规则3.3禁止对有符号整数进行位操作符运算 位操作符、、、、^、|)应该只用于无符号整型操作数。 错误示例 int data ReadByte(); int a data 24;推荐做法(为简化示例代码此处假设ReadByte函数实际不存在返回值小于0的情况) unsigned int data (unsigned int)ReadByte(); unsigned int a data 24;规则3.4禁止整数与指针间的互相转化 指针的大小随着平台的不同而不同强行进行整数与指针间的互相转化降低了程序的兼容性在转换过程中可能引起指针高位信息的丢失。 错误示例 char *ptr ...; unsigned int number (unsigned int)ptr;推荐做法 char *ptr ...; uintptr_t number (uintptr_t)ptr;规则3.5禁止对指针进行逻辑或位运算、||、!、、、、、^、| 对指针进行逻辑运算会导致指针的性质改变可能产生内存非法访问的问题。 下面是错误的用法 BOOL dealName(const char *nameA, const char *nameB) {...if (nameA)...if (!nameB)... }下面是正确的用法 BOOL dealName(const char *nameA, const char *nameB) {...if (nameA ! NULL)...if (nameB NULL)... }例外 为检查地址对齐而对地址指针进行的位运算可以作为例外。 规则3.6循环次数如果受外部数据控制需要校验其合法性 如下示例中由于循环条件受外部输入的报文内容控制可进入死循环 unsigned char *FindAttr(unsigned char type, unsigned char *msg, size_t inputMsgLen) {...msgLength ntohs(*(unsigned short *)msg[RD_LEA_PKT_LENGTH]);...while (msgLength ! 0) {attrType msg[0];attrLength msg[RD_LEA_PKT_LENGTH];...msgLength - attrLength;msg attrLength;}... }此例中需要检查报文的实际可读长度报文内容提供的循环增量避免为0以防止缓冲区溢出。 4.内存 规则4.1内存申请前必须对申请内存大小进行合法性校验 内存申请的大小可能来自于外部数据必须检查其合法性防止过多地、非法地申请内存。不能申请0长度的内 存。 例如 int Foo(int size) {if (size 0) { //error...}...char *msg (char *)malloc(size);... }规则4.2内存分配后必须判断是否成功 char *msg (char *)malloc(size); if (msg ! NULL) {... }规则4.3禁止引用未初始化的内存 malloc、new分配出来的内存没有被初始化为0要确保内存被引用前是被初始化的。 以下代码使用malloc申请内 存在使用前没有初始化 int *CalcMetrixColomn( int **metrix ,int *param, size_t size ) {int *result NULL;...size_t bufSize size * sizeof(int);...result (int *)malloc(bufSize);...result[0] metrix[0][0] * param[0];...return result; }规则4.3禁止引用未初始化的内存 以下代码使用memset_s()对分配出来的内存清零。 int *CalcMetrixColomn(int **metrix ,int *param, size_t size) {int *result NULL;...size_t bufSize size * sizeof(int);...result (int *)malloc(bufSize);...int ret memset_s(result, bufSize, 0, bufSize); //【修改】确保内存被初始化后才被引...result[0] metrix[0][0] * param[0];...return result; }规则4.4内存释放之后立即赋予新值 悬挂指针可能会导致双重释放double-free以及访问已释放内存的危险。消除悬挂指针以及消除众多与内存相 关危险的一个最为有效地方法就是当指针使用完后将其置新值。 如果一个指针释放后能够马上离开作用域因为它 已经不能被再次访问因此可以无需对其赋予新值。 示例 char *message NULL; ... message (char *)malloc(len); ... if (...) {free(message); //在这个分支内对内存进行了释放message NULL; //释放后将指针赋值为NULL } ... if (message ! NULL) {free(message);message NULL; }规则4.5禁止使用realloc()函数 realloc()原型如下 void *realloc(void *ptr, size_t size);随着参数的不同其行为也是不同。 1 当ptr不为NULL且size不为0时该函数会重新调整内存大小并将新的内存指针返回并保证最小的size的内容不变 2 参数ptr为NULL但size不为0那么行为等同于malloc(size) 3 参数size为0则realloc的行为等同于free(ptr)。 由此可见一个简单的C函数却被赋予了3种行为这不是一个设计良好的函数。虽然在编码中提供了一些便利性但是却极易引发各种bug。 5.文件输入/输出 规则5.1创建文件时必须显式指定合适的文件访问权限 创建文件时如果不显式指定合适访问权限可能会让未经授权的用户访问该文件。 下列代码没有显式配置文件的访问权限。 int fd open(fileName, O_CREAT | O_WRONLY); //【错误】缺少访问权限设置推荐做法 int fd open(fileName, O_CREAT | O_WRONLY, S_IRUSR|S_IWUSR);
http://www.w-s-a.com/news/601100/

相关文章:

  • 苏州建站仿站东莞排名推广
  • 大中小网站的区分wordpress个人主页主题
  • 商务网站建设的可行性分析包括小程序源码网免费
  • 永州网站建设收费标准重庆网站建设公司夹夹虫专业
  • python做网站多少钱wordpress 2.8
  • 深圳网站平台网站开发工作程序怎么写
  • 自己可以接单做网站吗wordpress 添加自定义按钮
  • 网站首页权重宣传页制作
  • 智能网站建设软件有哪些方面网页的建设
  • 石铜路网站建设生鲜电商网站开发
  • 怎么提高网站加载速度慢网站的轮播怎么做的
  • 网络网站推广优化建筑工程教育网官方网站
  • 旅行社网站策划做网站编辑好还是美工好
  • 珠海做网站找哪家好在线磁力搜索神器
  • 做网站优化有必要wordpress导航栏字体
  • 中山网站建设半江红沈阳免费网站建站模板
  • 工信部网站备案管理系统网站备案负责人 更换
  • 我要做个网站该怎么做怎么做电商平台网站
  • wordpress教程 网站标题莱芜大众网
  • 网站建设业务终止合作范本主机公园wordpress
  • 口碑好企业网站建设网站建设与什么专业有关
  • 助贷获客系统快速优化排名公司推荐
  • 重庆做网站优化推广的公司企业网站如何进行定位
  • 高密市赏旋网站设计有限公司山东广饶县建设局网站
  • 成都哪里有网站开发公司网业分离是什么
  • 购物导购网站开发女孩学建筑学好找工作吗
  • 做网站沈阳掌握夏邑进入公众号
  • 怎么做自动提卡网站谷歌推广怎么做
  • 大同网站建设熊掌号wordpress 首页单页
  • 青岛网站美工成都优秀网站建设