Skip to content

연산자

SafeC는 C의 모든 연산자에 더해 오버플로 제어를 위한 SafeC 고유 확장을 지원합니다. 이 페이지는 모든 연산자와 그 우선순위, 결합 방향에 대한 완전한 레퍼런스입니다.

산술 연산자

이항 산술

연산자설명예시
+덧셈a + b
-뺄셈a - b
*곱셈a * b
/나눗셈a / b
%나머지 (모듈로)a % b

단항 산술

연산자설명예시
+x단항 플러스 (항등)+a
-x단항 부정-a

증가와 감소

연산자설명예시
++x전위 증가 (증가 후 반환)++counter
x++후위 증가 (반환 후 증가)counter++
--x전위 감소 (감소 후 반환)--index
x--후위 감소 (반환 후 감소)index--
c
int x = 5;
int a = ++x;   // x는 6, a는 6
int b = x++;   // b는 6, x는 7
int c = --x;   // x는 6, c는 6
int d = x--;   // d는 6, x는 5

오버플로 인지 산술

SafeC는 명시적인 오버플로 제어를 위한 연산자 변형을 추가합니다. 자세한 사용법은 오버플로 연산자를 참고하십시오.

연산자설명동작
+|래핑 덧셈2의 보수 랩어라운드
-|래핑 뺄셈2의 보수 랩어라운드
*|래핑 곱셈2의 보수 랩어라운드
+%포화 덧셈최소/최대값으로 클램프
-%포화 뺄셈최소/최대값으로 클램프
*%포화 곱셈최소/최대값으로 클램프

대입 연산자

단순 대입

c
int x = 42;
x = 100;

복합 대입

복합 대입 연산자는 산술 또는 비트 연산과 대입을 결합합니다. a op= ba = a op b와 동등합니다.

연산자설명동등한 표현
+=더하고 대입a = a + b
-=빼고 대입a = a - b
*=곱하고 대입a = a * b
/=나누고 대입a = a / b
%=나머지를 구하고 대입a = a % b
&=비트 AND 후 대입a = a & b
|=비트 OR 후 대입a = a | b
^=비트 XOR 후 대입a = a ^ b
<<=왼쪽 시프트 후 대입a = a << b
>>=오른쪽 시프트 후 대입a = a >> b
c
int x = 10;
x += 5;     // x는 15
x -= 3;     // x는 12
x *= 2;     // x는 24
x /= 4;     // x는 6
x %= 5;     // x는 1

uint32_t flags = 0xFF00;
flags &= 0x0F0F;    // flags는 0x0F00
flags |= 0x00F0;    // flags는 0x0FF0
flags ^= 0x0FF0;    // flags는 0x0000

비교 연산자

연산자설명예시
==같음a == b
!=다름a != b
<미만a < b
>초과a > b
<=이하a <= b
>=이상a >= b

모든 비교 연산자는 bool을 반환합니다.

논리 연산자

연산자설명예시
&&논리 AND (단락 평가)a && b
||논리 OR (단락 평가)a || b
!논리 NOT!a

단락 평가(short-circuit evaluation): &&는 왼쪽 피연산자가 false이면 오른쪽 피연산자를 평가하지 않고, ||는 왼쪽 피연산자가 true이면 오른쪽 피연산자를 평가하지 않습니다.

c
// 단락 평가는 *평가 순서*에 영향을 줄 뿐, unsafe 역참조 규칙에는
// 영향을 주지 않습니다: &&가 ptr이 non-null일 때만 실행되도록 보장하더라도
// *ptr에는 여전히 'unsafe'가 필요합니다 — 컴파일러는 흐름 민감한
// 좁히기(narrowing)를 수행하지 않습니다.
unsafe {
    if (ptr != (int*)0 && *ptr > 0) {
        // &&' 덕분에 *ptr은 ptr이 non-null일 때만 평가됩니다
    }
}

비트 연산자

연산자설명예시
&비트 ANDa & b
|비트 ORa | b
^비트 XORa ^ b
~비트 NOT (보수)~a
<<왼쪽 시프트a << n
>>오른쪽 시프트a >> n
c
// 이진 리터럴 문법은 없습니다 (리터럴과 한정자 참고) — 대신 16진수
// 등가값을 쓰십시오. flags = 0xC = 0b1100, mask = 0xA = 0b1010.
uint32_t flags = 0xC;
uint32_t mask  = 0xA;

uint32_t and_result = flags & mask;   // 0x8  (0b1000)
uint32_t or_result  = flags | mask;   // 0xE  (0b1110)
uint32_t xor_result = flags ^ mask;   // 0x6  (0b0110)
uint32_t not_result = ~flags;         // 모든 비트가 반전됨

uint32_t shifted = 1 << 4;           // 16 (비트 4가 설정됨)

멤버 접근 연산자

연산자설명예시
.값 멤버 접근point.x
->포인터 멤버 접근ptr->x
::스코프 결정 / 메서드 정의Point::length()

. 연산자는 값과 참조의 필드에 접근합니다. -> 연산자는 한 번에 포인터를 역참조하면서 필드에 접근합니다.

c
struct Point { double x; double y; };

struct Point p = {3.0, 4.0};
double x1 = p.x;            // 값 접근

// raw pointer를 얻고 이를 ->로 역참조하는 것 모두 'unsafe'가 필요합니다 —
// '&stack Point'에서 'Point*'로의 암묵적 변환은 없습니다.
struct Point *ptr;
unsafe { ptr = (struct Point*)&p; }
double x2;
unsafe { x2 = ptr->x; }      // 포인터 역참조 + 접근
// (*ptr).x와 동등함

:: 연산자는 메서드 정의와 정적 스코프 결정에 사용됩니다.

c
double Point::length() const {
    return sqrt_d(self.x * self.x + self.y * self.y);
}

첨자 연산자

배열과 슬라이스의 인덱싱은 []를 사용합니다. 안전한 컨텍스트에서는 접근이 경계 검사됩니다.

c
int arr[5] = {10, 20, 30, 40, 50};
int x = arr[2];              // 30 (경계 검사됨)

[]int s = arr[1..4];
int y = s[0];                // 20 (슬라이스 길이를 기준으로 경계 검사됨)

삼항 연산자

조건(삼항) 연산자는 조건에 따라 두 표현식 중 하나를 평가합니다.

c
condition ? then_expr : else_expr
c
int x = 10;
int y = 20;
int max = (x > y) ? x : y;       // max는 20

const char *label = (count == 1) ? "item" : "items";

삼항 연산자는 우선순위가 매우 낮습니다 — 복잡한 조건에는 명확성을 위해 괄호를 사용하십시오.

콤마 연산자

C와 동일하게 동작합니다: (e1, e2, ..., eN)은 모든 피연산자를 왼쪽에서 오른쪽으로 순서대로 평가하여 부수 효과를 발생시키며, 전체 표현식의 타입과 값은 마지막 피연산자의 것입니다 — 앞선 피연산자들의 값은 버려집니다.

c
int a; int b;
int x = (a = 1, b = 2, a + b);   // x는 3

int i = 0;
int j = 10;
for (; i < j; i++, j--) {
    // i는 증가, j는 감소
}

C 스타일의 콤마로 구분된 다중 변수 선언 역시 동작하며, for 루프의 초기화절로도 사용할 수 있습니다.

c
for (int i = 0, j = 10; i < j; i++, j--) {
    // i는 증가, j는 감소
}

int a, b = 5, c;   // a와 c는 초기화되지 않음, b는 5

주소 연산자와 역참조

연산자설명예시
&주소 연산자 (리전 한정 참조를 생성)&x
*역참조 (포인터/참조를 통해 값에 접근)*ptr
c
int x = 42;
&stack int ref = &x;         // 리전 한정 참조
int y = *ref;                // 역참조: y는 42

리전 한정 참조에 대한 자세한 내용은 메모리와 리전을 참고하십시오.

연산자설명예시
(T)expr명시적 캐스트(double)x
sizeof(T)타입의 바이트 크기sizeof(int)
sizeof(expr)표현식 타입의 바이트 크기sizeof(x)
alignof(T)타입의 정렬 요구사항alignof(double)
c
int x = 42;
double d = (double)x;        // 명시적 캐스트

long s1 = sizeof(int);       // 4
long s2 = sizeof(x);         // 4
long a = alignof(double);    // 8 (플랫폼에 따라 다름)

typeof, fieldcount, sizeof...컴파일 타임 인트로스펙션을 참고하십시오.

연산자 우선순위

높은 순위부터 낮은 순위까지:

우선순위연산자결합 방향
1 (최고)() [] . -> x++ x--왼쪽에서 오른쪽
2++x --x +x -x ! ~ * & (T) sizeof alignof오른쪽에서 왼쪽
3* / % *| *%왼쪽에서 오른쪽
4+ - +| -| +% -%왼쪽에서 오른쪽
5<< >>왼쪽에서 오른쪽
6< <= > >=왼쪽에서 오른쪽
7== !=왼쪽에서 오른쪽
8&왼쪽에서 오른쪽
9^왼쪽에서 오른쪽
10|왼쪽에서 오른쪽
11&&왼쪽에서 오른쪽
12||왼쪽에서 오른쪽
13? :오른쪽에서 왼쪽
14= += -= *= /= %= &= ^= |= <<= >>=오른쪽에서 왼쪽
15 (최저),왼쪽에서 오른쪽

연산자 오버로딩

구조체 타입은 operator+, operator- 등의 이름을 가진 메서드를 정의하여 이항 연산자를 오버로드할 수 있습니다. 자세한 내용은 함수를 참고하십시오.

오버로드 가능한 연산자: +, -, *, /, %, ==, !=, <, >, <=, >=.

MIT 라이선스로 배포됩니다.