关注

C语言中的运算符

运算符

各类数值型数据间的混合运算

  • 整型、浮点型、字符型数据可以进行混合运算,如:

       10 - 'a' * 1.5
    =  10 - 97 * 1.5     // 保证参与运算的都是数字(字符`a`的ASCII码是97)   
    =  10.0 - 97.0 * 1.5 // 不同数据类型参与运算时,编译器会自动转换为同一类型后运算(隐式类型转换)
    

    解释:整型、浮点型、字符型能进行混合运算,核心原因是它们都属于数值型数据 ——字符本质是特殊的数值型(参与数值计算时使用ASCII码,取值范围是0~127)

    运算规则若参与运算的两个数类型不同,会先将类型转换为一致后再运算。转换规则分为隐式转换显示转换

隐式转换

隐式转换又被称作自动类型转换,由编译系统自动控制,规则是将低等级类型提升为高等级类型。

语法:

高等级类型 变量名 = 低等级类型变量;

转换关系(从低到高):

int → unsigned int → long → double

注意:intunsigned int 的转换顺序可能因平台(如操作系统位数)和编译器不同存在差异,需结合具体环境判断。

char /short → int(必然转换)

float → double(必然转换,C 语言默认以双精度浮点型(double)进行浮点运算,因此 float 类型参与运算时会自动隐式转换为 double)

关键注意事项:

混合运算中的类型转换仅在运算过程中临时生效,不会改变原变量的类型和内存的存储形式(所谓的类型提升,其实就是系统运算时, 将原本的数据产生一份副本,由副本数据参与计算,计算完毕,副本销毁,原数据不受影响)。

举例:

int a = 10;           // a的类型始终是int
double c = a + 22.5;  // 运算时a临时转换为double,等价于 10.0 + 22.5,其实就是a的double类型的副本参与计算
a = 21;               // a仍然是int,变量一旦申请,其内存大小不会发生改变
float c2 = a + 22.5f; // 运算时a临时转换为float,等价于 21.0f + 22.5f,其实就是a的float类型的副本参与计算
a = 10;               // a保持int类型不变

显示转换

显示转换

显示转换又被称作强制类型转换,由程序员手动指定转换类型。

语法:

(type)(表达式)

语法说明:

  • (double)a:将变量a的值转换为double类型。
  • (int)(x+y):将表达式x+y的结果转换为int类型(括号必须包含整个表达式,否则转换x
  • (int) x+y:仅将变量x转换为int类型,再与y进行计算(括号仅作用于x

举例:

double a = 2, b = 3;   // a,b均为double类型
double c = (int)a + b; // 第1步:显示将a转换为int(值为2);第2步:混合运算时int自动转换为double,最终等价于 2.0 + 3.0
double num1 = 12.55;   // num11是double类型
int num2 = (int)num1;  // 显示将num1转换为int类型,浮点型转整型,会舍弃小数部分
printf("%d\n", num2);  // 输出结果:12(浮点型转整型,舍弃小数部分,保留整数部分)
num1 = 15;             // num1的类型仍然是double(值为15.0)

关键注意事项:

  1. 强制类型转换仅在运算过程中临时改变值的类型,不会修改原变量的类型和内存存储形式;
  2. 浮点型转整型时直接舍弃小数部分,不进行四舍五入
  3. 转换后的类型需与接收变量的类型匹配,避免数据溢出或精度丢失。

案例:强制类型转换实践

  • 需求:验证强制类型转换对原变量类型的影响

  • 代码

    #include <stdio.h>
    
    int main(int argc,char *argv[])
    {
        float x;
        int i;
    
        x = 3.6f;  // float类型变量赋值时,同类型常量添加f/F后缀
        i = (int)x;// 运行时强制将x转换为int,此时参与运算的实际上是x的副本
        // 输出结果:x=3.600000,i=3,%f默认输出6位小数
        printf("x=%f, i=%d\n", x, i);
    
        return 0;
    }
    

说明:变量x的类型始终为float,强制类型转换仅影响赋值给i的值,不改变x本身的类型和值,究其原因,参与运算的是副本。

C运算符和C表达式

C运算符
C 运算符(完整列表)
序号名称符号序号名称符号
1算术运算符+、-、*、/、%、++、--8指针运算符*、&
2关系运算符>、<、>=、<=、==、!=9字节数运算符sizeof
3逻辑运算符`&&、、!`10
4位运算符`<<、>>、~、、^、&`11强制类型转换运算符
5赋值运算符=、+=、-=、*=、/=、%=12分量运算符.、->
6条件运算符?:13函数调用运算符()
7逗号运算符,
C 表达式

定义:运算数(常量、变量、表达式)和运算符按C语法规则连接而成的式子(表达式 = 运算数 + 运算符)

名称举例结果类型与说明
算数表达式2+6.7∗3.52 + 6.7 * 3.52+6.73.5数值类型(int或double等,取决于运算数类型)
关系表达式x>0、y<z+6x > 0、y < z + 6x>0y<z+6布尔类型(C语言用0表示假,非0表示真)
逻辑表达式x > 0 && y > 0 布尔类型(C语言用0表示假,非0表示真)
赋值表达式a =5.6、sum += i、b=c=d=5左侧变量的类型,运算顺序自右向左
逗号表达式x = 3, y += 4, z -= 8最后一个表达式的类型,结果为最后一个表达式的值
C 语言运算符优先级与结合性

C 语言通过优先级和结合性规定表达式的求值顺序:优先级高的运算符先执行;优先级相同时,按结合性顺序执行

简化优先级表(从高到低):

优先级运算符类别运算符示例结合性
1括号、下标、成员访问()、[]、.、->从左向右
2后缀自增 / 自减a++、a–从左向右
3前缀自增 / 自减、逻辑非等++a、–a、!、sizeof、&、-(负号)从右向左
4强制类型转换(type)从右向左
5算术乘除、取余*、/、%从左向右
6算术加减+、-从左向右
7位左移 / 右移<<、>>从左向右
8关系运算符(比较大小)>、<、>=、<=从左向右
9关系运算符(相等判断)==、!=从左向右
10位与&从左向右
11位异或^从左向右
12位或|从左向右
13逻辑与&&从左向右
14逻辑或||从左向右
15条件运算符?:从右向左
16赋值运算符(含复合赋值)=、+=、-=、*=、/= 等从右向左
17逗号运算符,从左向右

算数运算符

运算符功能类型注意事项
+加法/正值双目/单目单目时表示正值,如 +5
-减法/负值双目/单目单目时表示负值,如 -5
*乘法双目
/除法双目除数不能为0,整型相除结果为整型,如 1/2=0
%取余(模运算)双目仅适用于整型;结果符号与被除数一致;
++自增单目使变量值增1
--自减单目使变量值减1

核心规则:

  1. 运算顺序与数学一致:先乘除取余,后加减;
  2. 整型相除:结果仅保留整数部分,舍弃小数(如 7/6=1、4/7=0、1/2=0);
  3. 取余运算:结果的符号与被除数一致(如 5%2=1、-5%2=-1、5%-2=1)。

面试题:

  1. 1/2 + 1/2的结果是多少? 答案:0(两个整数相除,结果为0, 0+0=0)
  2. 1.0/2 + 1.0/2的结果是多少? 答案:1.0(浮点型运算,0.5+0.5=1.0)
自增、自减运算符(++/–)

**作用:**使变量值增1或者减1,适用于算数类型(整型、字符型、浮点型等)的可修改左值,实践中常用整型和字符型变量。

**核心区别:**运算符位置决定变量值的更新时机。

++i/–i(前缀自增/自减)

**运算规则:**先更新变量值,后使用变量(先计算,后使用,自己计算,别人使用)

  • 步骤1:变量值自增1(i = i + 1)或自减1(i = i -1)
  • 步骤2:使用更新后的变量值参与计算、赋值、比较等操作。

举例:

int i = 1;  // 变量i
int x = ++i;// 等价于 i = i + 1 (i=2), x = i (x=2)
printf("i=%d,x=%d\n", i, x);  // i=2,x=2
printf("i=%d,x=%d\n", ++i, x);// i=3,x=2,i = i + 1 = 2 + 1 = 3, ++i 可以理解,int temp = ++i
int a = 1;
printf("a=%d\n", ++a); // a=2
i++/i–(后缀自增/自减)

**运算规则:**先使用变量,后更新变量(先使用,后计算

  • 步骤1:使用变量当前值参与赋值、计算、比较等操作。
  • 步骤2:变量值自增1(i = i + 1)或自减1(i = i -1)

举例:

int i = 1;  // 变量i
int x = i++;// 等价于 x = i (x=1),i = i + 1 (i=2)
printf("i=%d,x=%d\n", i, x);  // i=2,x=1
printf("i=%d,x=%d\n", i++, x);// i=2,x=1, ++i 可以理解,int temp = i++

int a = 1;
printf("a=%d\n", a++); // a=1  

// 以上两行代码等价于
// int a = 1
// int temp = a++;
// printf("a=%d\n", temp);// a=1

总结与注意事项:

  1. 无论前缀还是后缀,变量本身的最终值都增1或者减1,差异仅在于参与其他运算时使用的是更新前还是更新后的值。
  2. 禁止用于常量或表达式:如--5(常量)、(i+j)++(表达式)、MAX_VAL++(宏定义)均为非法
  3. 避免复杂嵌套:如i++ + ++i - --i + i--属于未定义行为(UB),不同编译器可能给出不同结果,正式开发中严禁使用。
课堂练习
  1. 根据如下代码,推导其结果!

    int i = 1;
    int n = i++ + ++i - --i + i++;
    
  2. 根据如下代码,推导其结果!

    int i = 10;
    int j = 5;
    int k = i++ + ++i - --j - i--;
    

警告: 以上练习仅用于理解运算符机制,实际编程中严禁使用此类嵌套写法,因 C 标准未定义其行为,不同编译器可能产生不同结果。

赋值运算符

基本赋值运算符(=)

**作用:**将右侧运算数(常量、变量、表达式)的值存入左侧变量的内存单元。

语法:

变量 = 表达式;

举例:

int a = 5;    // 将常量5赋值给变量a(初始化)
int b = a;    // 将变量a的值赋值给变量b
int c = a + b;// 将表达式a+b的值赋值给变量c
a = a + 1;    // 将表达式a+1的结果赋值给a(a的值增1),可以写作 a++,++a

核心规则:

  1. 运算顺序:自右向左(先计算右侧表达式,再赋值给左侧变量)
  2. 左侧必须是可修改的变量(左值),不能是常量或表达式,如5 = a,a + b = 3均非法
  3. 赋值表达式的值等于左侧变量的最终值,如b = a = 5中,a = 5的值为5,再赋值给b,最终b = 5
类型转换规则(赋值时)

若赋值运算符=两侧类型不一致,会自动进行类型转换,转换规则如下:

源类型目标类型转换规则举例
浮点型(double、float)整型(short、int、long)舍弃小数部分,仅保留整数部分int a = 5.9 → a = 5
整型(short、int、long)浮点型(double、float)数值不变,以目标浮点型格式存储double b = 5 → b = 5.000000
字符型(char)整型(short、int、long)字符的ASCII码存入整型低8位,高位补0int c = 'A' → c = 65
长整型短整型截取低字节数据,可能导致数据溢出short d = 32768(int) → 溢出
复合赋值运算符

复合赋值运算符基本赋值运算符与算数运算符/位运算符的结合,简化代码书写。

语法:

变量 运算符= 表达式;  // 等价于 变量 = 变量 运算符 (表达式)

注意:复合赋值运算符优先级低,右侧表达式会优先计算。

常见复合赋值运算符:

运算符等价形式举例结果
+=a = a + bint a=1; a+=3;a=4(1+3)
-=a = a - bint a=5; a-=2;a=3(5-2)
*=a = a * bint a=3; a*=4;a=12(3*4)
/=a = a / bint a=8; a/=2;a=4(8/2)
%=a = a % bint a=7; a%=3;a=1(7%3)
&=a = a & bint a=5; a&=6;a=4(5&6)
`=``a = ab`
^=a = a ^ bint a=5; a^=6;a=3(5^6)
<<=a = a << bint a=2; a<<=1;a=4(2<<1)
>>=a = a >> bint a=4; a>>=1;a=2(4>>1)

注意事项:

  1. 复合赋值运算符的优先级与基本赋值运算符相同(仅高于逗号运算符);
  2. 避免混淆=(赋值)和==(相等判断):a=5表示将 5 赋值给 a,a==5表示判断 a 是否等于 5;
  3. 表达式两侧若有复杂运算,需加括号明确优先级(如a += (b*c),而非a += b*c,虽结果一致但可读性更佳)。

关系运算符

**作用:**比较两个运算数的大小或相等关系,结果为布尔类型(C语言用0表示假,非0表示真)。

常用关系运算符(均为双目运算符):

运算符功能举例结果(假设 a = 5, b = 4)
>大于a > b1(true-真)
<小于a < b0(false-假)
>=大于等于a >= 51(true-真)
<=小于等于b <= 30(false-假)
==等于a == 51(true-真)
!=不等于a != b1(true-真)

注意:C标准给我们返回的真值为1,但是我们在使用的使用,可以用任意非0作为真值。

运算数支持类型:

变量、常量(字面量(3,3.14)、符号常量(#define)、const修饰变量)、表达式,如:

a > b;           // 变量 vs 变量
5 > 6;           // 常量 vs 常量
(a + b) > (c * 2)// 表达式 vs 表达式

关键注意事项:

  1. 避免链式比较:C语言不推荐0 <= score <= 100这类链式写法,逻辑上会报错,编译不报错

    错误原因:编译器按左结合性依次计算,如0 <= score <= 100,等价于(0 <= score) <= 100,结果永远为,无论score是否在0~100范围内。

    正确写法:使用逻辑与运算符score >= 0 && score <= 100

  2. 浮点型相等比较需要用差值法:由于浮点型存储精度限制(如1.1无法精确存储),直接用==判断相等会导致逻辑错误。

    错误示例:

    float a = 1.1f + 1.2f;  // 2.300000
    float b = 2.3f;
    printf("a=%.20f,b=%.20f,%d\n",a,b,a==b); // a=2.30000019073486328125,b=2.29999995231628417969,0
    

    正确写法:判断两数差值的绝对值是否小于极小值(如1e-6,即0.000001),需引入math.h头文件使用fabs函数(取绝对值)

    #include <math.h> // C语言数学库
    
    #define EPS 1e-6  // 定义误差允许范围  
    
    if (fabs(a - b) < EPS)  // 为什么要用绝对值函数,要求两个数相减的差值为正值  4 - 5 = |-1| = 1  5 - 4 = |1| = 1
    {
    	// 两数相等   double a = 56, b = 99;    if (fabs(a - b) < 100)
    }
    

浮点型比较总结:

操作类型正确方式错误方式
浮点数相等比较fabs(a - b) < EPS(EPS=1e-6)a == b
浮点数大小比较直接使用><>=<=-
浮点数零值比较fabs(a) < EPSa == 0.0

逻辑运算符

**作用:**对布尔类型的运算数进行逻辑运算,结果仍然为布尔类型(0表示假,非0表示真)

常用逻辑运算符:

运算符名称类型运算规则短路效果
!逻辑非单目真 → 假,假 → 真无(仅一个运算数)
&&逻辑与双目全真则真,有假则假左侧为假时,右侧不执行
``逻辑或双目
逻辑非!
  • 仅作用于右侧运算数,优先级较高
  • 仅同一运算数取非奇数次,结果与原值相反;取非偶数次,结果与原值相同。

举例:

int a = 5, b = 0;
printf("%d\n", !a);  // 0(a非0为真,!真=假)
printf("%d\n", !b);  // 1(b=0为假,!假=真)
printf("%d\n", !(a % 2 != 0)); // 0(a%2!=0为真,!真=假)
printf("%d\n", !!a); // 1(!!真=真,自右向左)   
逻辑与&&
  • 运算顺序:自左向右
  • 短路效果:若左侧运算数(表达式)为假,右侧运算数不再执行(因最终结果必为假,无需计算右侧)。

举例:

int score = 90;

printf("%d\n", score >= 0 && score <= 100); // 判断成绩是否在0~100以内,输出结果:1

int x = 3, y = 5;
if (x > y && y++)  // 此时触发短路
{ 
    // 不执行
}
printf("y=%d\n", y); // 输出y=5
逻辑或||
  • 运算顺序:自左向右
  • 短路效果:若左侧运算数(表达式)为真,右侧运算数不再执行(因最终结果必为真,无需计算右侧)。

举例:

int year = 2025;
// 闰年判断:能被4整除且不能被100整除,或者能被400整除,算数运算符 > 关系运算符 > 逻辑运算符(&& ||)
printf("%d\n",((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); // 输出 0

// 成绩的非法输入校验:成绩(0~100)
int score = 90;
printf("%d\n", score < 0 || score > 100);  // 0
       
int x = 3, y = 5;
if (x < y || y++)  // 此时触发短路
{ 
    // 执行
}
printf("y=%d\n", y); // 输出y=5

短路效果的应用场景:

  1. 避免非法操作:如ptr != NULL && *ptr == 5(先判断指针非空,再访问指针指向的值,避免空指针异常);
  2. 优化性能:无需计算所有运算数即可确定结果时,短路效果可减少运算次数。

逗号运算符

作用:将多个表达式串联成一个表达式(又称作顺序求值运算符),按从左到右的顺序执行每个表达式。

语法:

表达式1,表达式2,...表达式n;

核心规则:

  1. 求值顺序:从左往右依次计算每个表达式的值
  2. 最终结果:整个逗号表达式的值等于最后一个表达式的值
  3. 优先级:逗号运算符的优先级是所有运算符中,优先级最低的。需要注意括号的使用。

举例:

#include <stdio.h>

int main()
{
    // 变量,函数中的逗号,叫做逗号分隔符
	int a = 0, b = 0;  // 变量声明中使用的是逗号分隔符,非逗号表达式,函数参数如printf("%d,%d",a,b);中是逗号分隔符。
    
    // 整体是赋值表达式,(a = 3, b = 5, a + b)内是逗号表达式,结果是最后一个表达式的结果,8
    int result = (a = 3, b = 5, a + b);  
    
    // 综合条件判断的逗号表达式
    int x = 10, y = 20;
    int max = (x++, y++, (x > y) ? x : y);   // (x > y) ? x : y ,语法:表达式 ? 为真执行的语句 : 为假执行的语句
    printf("max=%d\n", max); // max=21
    
    return 0;
    
}

建议:如果无法区分逗号表达式和赋值表达式,就看谁最后执行,谁最后执行,就是谁!

关键注意事项:

  1. 区分逗号表达式与逗号分隔符:变量声明(如int a=0, b=0)、函数参数(如printf("%d,%d", a, b))中的逗号是分隔符,而非逗号表达式;

  2. 括号的重要性:若省略括号,逗号运算符的低优先级会导致逻辑错误。

    例如int result = a=3, b=5, a+b等价于(int result = a=3), b=5, a+b,result 的值为 3(而非 8)。

    如果表达式int result = (a=3, b=5, a+b),此时result的值为8。

位运算

**作用:**直接对数据的二进制位(bit)进行运算,常用于嵌入式开发、底层编程、数据加密等场景。

**前提:**参与位运算的操作数需要先转换为二进制(signed类型按补码存储,unsigned类型按原码存储)。

按位取反(~)
  • **类型:**单目运算符
  • **规则:**对数据的每一个二进制位取反(0→1,1→0
  • **注意:**整数在内存中以补码形式存储,取反需要结合补码规则转换为十进制(如:~5 = -6

演示:以8位二进制为例

十进制二进制补码按位取反十进制结果
50000 01011111 1010-6

举例:

printf("%d\n", ~5);  // 输出:-6(32位系统中补码运算结果)
按位与(&)
  • **类型:**双目运算符
  • **规则:**对应二进制位均为1时,结果为1;否则为0(有0则0)

演示:以8位二进制为例

十进制二进制补码运算十进制二进制补码结果(二进制)结果(十进制)
50000 0101&60000 01100000 01004

举例:

printf("%d\n", 5 & 6); // 输出:4

常用场景:

  1. 按位清零:将特定位设为0(如num & 0xFFFFFFF将num的最低位设置为0,后续展开讲解)
  2. 提取特定位:获取数据的某几段(如num & 0x0F提取num的低4位)
按位或(|)
  • **类型:**双目运算符
  • **规则:**对应二进制位有一个为1时,结果为1;否则为0(有1则1)。

演示:以8位二进制为例

十进制二进制补码运算十进制二进制补码结果(二进制)结果(十进制)
50000 0101|60000 01100000 01117

举例:

printf("%d\n", 5 | 6); // 7

常用场景:

  1. 按位置1:将特定位设为1(如:num | 0x01将num的最低位设为1)
  2. 合并数据:将两个数据的不同位合并为一个数据。
按位异或(^)
  • **类型:**双目运算符
  • **规则:**对应二进制位相同则为0,不同则为1(相同为0,不同位1)

演示:以8位二进制为例

十进制二进制补码运算十进制二进制补码结果(二进制)结果(十进制)
50000 0101^60000 01100000 00113

举例:

printf("%d\n", 5 ^ 6); // 3

常用场景:

  1. 数据交换:无需临时变量交换整数(a = a ^ b; b = a ^ b; a = a ^ b
  2. 按位翻转:将特定为翻转(0 → 1,1 → 0
  3. 加密解密:与同一个秘钥异或两次可还原数据

面试题:

题目:不使用临时变量,如何实现两个变量的交换?位运算中的按位异或!

按位左移(<<)

**说明:**将原操作数的所有二进制位整体向左移动指定的位数。移位规则为“高舍低补”(高位溢出的二进制位直接丢弃,低位补0)。该规则与存储模式(大/小端)无关,仅取决于移位操作本身。

无符号左移
  • 语法:

    操作数 << 移动位数
    
  • **核心公式:**无溢出时,结果等价于 操作数∗2移动位数操作数 * 2^{移动位数}操作数2移动位数 (溢出后公式失效)

  • 举例:

    unsigned char a = 3 << 3;  // 结果为24 (3 * 2 ^ 3 = 24)
    unsigned int b = 5 << 4;   // 结果为80 (5 * 2 ^ 4 = 80)
    
有符号左移
  • **语法:**同上

  • **核心公式:**同上

  • 举例:

    char a = -3 << 3;   // 结果为-24 (-3 * 2 ^ 3 = -24)
    int b = 240 << 2;   // 结果为960 (240 * 2 ^ 4 = 960)
    
  • 推导:

    8位有符号 char:-3 << 3

    步骤二进制(8 位)说明
    原数 -3原码:10000011符号位 1(负),数值位 0000011
    反码:11111100原码符号位不变,数值位取反
    补码:11111101反码 + 1(运算基于补码)
    左移 3 位补码:11101000高位溢出丢弃,低位补 0
    移位后反码11100111补码 - 1(还原反码)
    移位后原码10011000反码符号位不变,数值位取反
    结果-24原码 10011000 对应十进制 - 24
  • 注意

    1. 有符号数的移位基于补码进行(运算过程:原码→反码→补码→移位→反码→原码→结果);
    2. 若移位后符号位被覆盖(如正数左移后溢出变为负数),公式不再适用,结果由补码规则决定
按位右移(>>)

**说明:**将原操作数的所有二进制位整体向右移动指定的位数。移位规则为"高补低舍"(低位溢出的二进制位直接丢失,高位由操作数类型决定补值)。

操作数高位补值规则移位类型
无符号数补0逻辑右移
有符号数补符号位(所有补的位置,1补1,0补0)算数右移

注意:大部分编译器(如GCC,Clang,MSVC)对有符号数均采用算数右移,仅极少数特殊平台例外。

语法:

操作数 >> 移动位数

**核心公式:**结果等价于 $ 操作数 / 2 ^{移动位数}$(向下取整)

无符号右移
  • 举例:

    unsigned char a = 3 >> 3;   // 结果为0 (3 / 2 ^ 3 = 0.375,向下取整为0)
    
有符号右移
  • 举例:

    char a = -3 >> 3;  // 结果为-1 (-3 / 2 ^ 3 = -0.375, 向下取整为-1)
    
  • 推导:

    8 位有符号 char演示:-3 >> 3

    步骤二进制(8 位)说明
    原数 -3补码:11111101运算基于补码
    右移 3 位(算术右移)补码:11111111高位补符号位 1,低位丢弃
    移位后反码11111110补码 - 1
    移位后原码10000001反码数值位取反
    结果-1原码 10000001 对应十进制 - 1

    移位运算完整流程

    原数据 → 二进制原码 → 二进制反码 → 二进制补码 → 执行移位操作 → 二进制反码(移位后补码逆运算) → 二进制原码 → 目标进制结果

转载自CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/p341953350/article/details/157477933

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--