有网站可以接设计的单子做吗那种退不掉的网站怎么做的
有网站可以接设计的单子做吗,那种退不掉的网站怎么做的,开发公司成本部职责岗位职责和流程,上海今天出什么大事件了前言#xff1a; 前文中#xff0c;我们系统学习了 namespace 机制#xff08;有效地解决了命名冲突问题#xff0c;包含指定访问、部分展开和全部展开三种使用方式#xff09;#xff0c;同时了解了 cin/cout 输入输出流#xff08;具备自动类型识别和支持自定义类…前言前文中我们系统学习了 namespace 机制有效地解决了命名冲突问题包含指定访问、部分展开和全部展开三种使用方式同时了解了 cin/cout 输入输出流具备自动类型识别和支持自定义类型两大优势以及编写了第一个C程序本文将为大家解析C语言与C在函数方面的主要区别。一、缺省参数这是一个非常实用且常用的特性允许你在定义函数时为参数指定一个“默认值”。如果调用函数时没有传递该参数编译器就会自动使用这个默认值。1.1 什么是缺省参数简单来说就是备胎 当你在调用函数时如果你给了实参就用你给的。如果你没给就用函数定义里预先写好的默认值。基本语法示例#include iostream using namespace std; // 这里 b 被指定为缺省参数默认值为 10 void printAdd(int a, int b 10) { cout a: a , b: b , sum: a b endl; } int main() { // 情况 1只传一个参数 // a 变成了 5b 自动使用默认值 10 printAdd(5); // 输出: a: 5, b: 10, sum: 15 // 情况 2传两个参数 // a 变成了 5b 使用传入的 20覆盖了默认值 printAdd(5, 20); // 输出: a: 5, b: 20, sum: 25 return 0; }1.2 核心规则非常重要1.2.1 规则一必须“从右往左”依次给出如果一个参数有了默认值那么它右边的所有参数都必须也有默认值你不能跳着给。错误写法void func(int a 10, int b, int c);原因a 有默认值但右边的 b 和 c 没有编译器不知道你传的参数是给谁的错误写法void func(int a, int b 10, int c);原因b 有默认值但右边的 c 没有正确写法void func(int a, int b 10, int c 20);从 b 开始往右全都有默认值1.2.2 规则二声明和定义不能同时给通常我们会把函数的声明在.h文件中和定义在.cpp文件中分开。 但是缺省参数只能出现一次通常建议写在声明中。// --- header.h --- // 建议在声明中指定默认值 void Func(int a 10); // --- main.cpp --- // 错误定义中再次指定即使值一样也不行 // void Func(int a 10) { ... } // 正确定义中不要写默认值 void Func(int a) { cout a endl; }1.3缺省参数的分类1.3.1全缺省参数//全缺省 void Func1(int a 10, int b 20, int c 30) { cout a a endl; cout b b endl; cout c c endl endl; } //调用 int main() { //全缺省的四种调用方式 Func1(); //输出a10 b20 c30 Func1(1); //输出a1 b20 c30 Func1(1, 2); //输出a1 b2 c30 Func1(1, 2, 3); //输出a1 b2 c3 return 0; }1.3.2半缺省参数//半缺省 //缺省参数从右往左且不能间隔跳跃传缺省参数 void Func2(int a, int b 10, int c 20) { cout a a endl; cout b b endl; cout c c endl endl; } int main() { //缺省调用没有缺省值的必须传参 Func2(100); //输出a100 b10 c20 Func2(100, 200); //输出a100 b200 c200 Func2(100, 200, 300); //输出a100 b200 c300 return 0; }1.4 常见的“坑”缺省参数单独使用很棒但和一个无参函数混合在一起使用容易造成二义性Ambiguity导致编译报错。#include iostream using namespace std; // 函数 1没有参数 void target() { cout 无参版本 endl; } // 函数 2带缺省参数 void target(int a 10) { cout 带缺省参数版本: a endl; } int main() { // target(5); // 没问题只能调用函数 2 // 报错二义性错误 // 编译器困惑是调用函数 1还是调用函数 2 并使用了默认值 target(); return 0; }二、函数重载函数重载是 C 中一个非常实用且基础的特性。简单来说它允许你在同一个作用域内给不同的函数起相同的名字只要它们的参数列表不同即可。2.1 什么是函数重载让我们看一个print函数的重载例子#include iostream using namespace std; // 1. 基础函数 void print(int i) { cout 正在打印整数: i endl; } // 2. 参数类型不同 void print(double d) { cout 正在打印浮点数: d endl; } // 3. 参数个数不同 void print(int i, int j) { cout 正在打印两个整数: i , j endl; } // 4. 参数顺序不同 (注意类型要不同才有意义) void print(int i, double d) { cout 先整数后浮点: i , d endl; } void print(double d, int i) { cout 先浮点后整数: d , i endl; } int main() { print(10); // 调用第 1 个 print(3.14); // 调用第 2 个 print(10, 20); // 调用第 3 个 print(10, 3.14); // 调用第 4 个 return 0; }2.2 构成重载的三个条件编译器区分同名函数的唯一依据是参数列表也叫函数签名只要满足以下任意一个条件就构成重载①参数个数不同②参数类型不同③参数顺序不同 (指不同类型的参数顺序互换)例如同一个 print 函数可以根据参数列表不同实现不同的函数重载。1. 基础函数void print(int i)2.同一个函数参数类型不同void print(double d)3.同一个函数参数个数不同void print(int i, int j)4.同一个函数参数的类型顺序不同void print(int i, double d)2.3 常见的“陷阱”2.3.1 情况A返回值类型不同不构成重载// 错误示例编译器会报错 int func(int a) { return a; } void func(int a) {}因为在调用函数时我们经常忽略返回值例如直接写func(10);。如果两个函数只有返回值不同编译器看到func(10)时根本无法判断你想调用哪一个它不知道你是否需要那个返回值。2.3.2 情况 B类型转换导致的歧义有时候你写的重载虽然语法正确但调用时会让编译器“左右为难”导致编译错误。void test(long a) { ... } void test(double a) { ... } int main() { test(10); // 报错 }原因 由于10是int类型所以它既可以转成long也可以转成double编译器觉得两者优先级一样不知道选谁。2.3.3 情况 C默认参数导致的歧义void func(int a) { cout A; } // 第二个参数有默认值 void func(int a, int b 10) { cout B; } int main() { func(5); // 报错 }原因 当你调用func(5)时既符合第一个函数也符合第二个函数因为第二个参数可以省略。编译器无法区分直接报错。三、内联函数在 C 中内联函数 (Inline Function) 是一个旨在提高程序运行效率的特性。简单来说它的作用是向编译器发出一个建议在调用该函数的地方不要进行普通的“函数跳转”和“上下文切换”而是直接将函数的代码“复制粘贴”到调用点。3.1 核心概念与工作原理1. 普通函数调用当程序调用一个普通函数时CPU 需要保存当前状态压栈跳转到函数所在的内存地址执行代码执行完毕后再跳回来出栈。这个过程称为函数调用开销即该过程为开辟函数栈帧2. 内联函数编译器直接将函数体内的代码插入到调用该函数的地方。这样就消除了调用和返回的开销但会增加最终可执行文件的大小代码膨胀这个过程省略了开辟函数栈帧提高了程序运行时的效率。3.2 语法与使用使用关键字inline来声明内联函数。通常内联函数的定义具体实现必须在头文件中或者在调用之前可见。#include iostream using namespace std; // 使用 inline 关键字 // 只是定义告诉编译器 add 长什么样并且建议内联 inline int add(int a, int b) { return a b; } int main() { int x 10, y 20; // 内联函数在这里展开 // 编译器会将下面这行代码实际上替换为 int result a b; int result add(x, y); cout result endl; return 0; }3.3 编译器的“拒绝权”重要的一点是inline只是对编译器的一个建议而不是命令编译器可以有权忽略这个建议。以下情况下编译器通常会拒绝内联而将其作为普通函数处理①函数体过大 包含复杂的逻辑。②包含循环语句 (for,while) 循环执行的时间通常远大于函数调用的开销内联意义不大。③包含递归 递归函数无法无限展开。④包含 switch 或 goto 语句。3.4 内联函数与宏定义C语⾔实现宏函数也会在预处理时替换展开但是宏函数实现很复杂很容易出错的且不⽅便调 试C设计了inline⽬的就是替代C的宏函数。例如实现宏函数ADD 完成两数相加#define ADD(a,b) ( (a)(b) )由该宏函数可能会引出如下问题①为什么不能加分号?进行条件判断和输出时会出现问题如if( ADD(2,3) 0)②为什么要加外⾯的括号?运算时的优先级如ADD(2,5) * 3 --- (2) (5) * 3③为什么要加⾥⾯的括号?运算时的优先级如ADD(x y, x | y); --- ( x y x | y )内联函数实现Add完成两数相加nline int Add(int a, int b) { return a b; }为什么通过内联函数可以很好的替代宏函数因为内联函数真正的函数。有类型安全检查参数处理正确且由编译器处理而非预处理器。3.5 内联函数的注意事项inline绝对不能声明和定义分离到两个⽂件分离会导致链接错误。因为inline被展开就没有函数地址链接时会出现报错。详细解释定义了如下三个文件文件一test.h声明func函数//test.h (声明func函数): inline void func();文件二 test.cpp定义func函数//test.cpp (定义func函数): #include test.h inline void func() { //... }文件三main.cpp 调用func函数//#include test.h int main() { func(); return 0; }关键分析当编译器编译main.cpp时发生了什么①预处理器把test.h的内容复制进来了。②编译器看到了func()的声明知道它是一个inline函数。③关键点编译器此时看不到test.cpp里的内容它找不到func的大括号{ ... }里的代码。结果编译器无法进行内联展开因为没代码可抄它只能退而求其次生成一条普通的汇编指令call func寄希望于链接器Linker稍后能找到这个函数的定义。核心问题分析为什么 “找不到” func的函数定义链接期问题原因①当编译器去编译 test.cpp文件时编译器看到了 inline void func() { ... }对于 inline 函数编译器通常认为“这个函数是为了给别人内联展开用的不需要生成一个可以被外部链接调用的‘全局函数符号’或者说符号是弱符号/仅本地可见”。原因②当你编译 test.cpp 时编译器是“与世隔绝”的它不知道 main.cpp 的存在也不知道 main.cpp 可能会在那边哭着喊着要调用 func()。当它在 test.cpp 里看到一个 inline 函数定义却发现 test.cpp 自己根本没用它时为了节省空间直接把它优化掉不生成汇编代码。最终崩溃链接错误当三个文件都编译完成时链接器将三个文件进行链接①它拿着 main.obj看到里面有一个“欠条”call func未解析的外部符号。②它去 test.obj 里找 func 的定义。③找不到 因为在编译 test.cpp 时func 作为内联函数并没有生成标准的全局符号。④报错LNK2019: unresolved external symbol (未解析的外部符号)。正确的做法因为编译器需要看到代码才能进行“复制粘贴”所以最好将内联函数的定义写在头文件 (.h) 里。#ifndef TEST_H #define TEST_H // 声明和定义都在头文件里 inline void func() { // 具体的实现代码... } #endif既然看到这里了不妨关注点赞收藏感谢大家若有问题请指正。