안녕하세요>.<
66.1에서는 va_start()두번째 인자로 int를 받고있고요
void printNumbers(int args, ...) // 가변 인자의 개수를 받음, ...로 가변 인자 설정 { va_list ap; // 가변 인자 목록 포인터 va_start(ap, args); // 가변 인자 목록 포인터 설정
66.2에서는 char*를 받고있습니다.
void printValues(char *types, ...) // 가변 인자의 자료형을 받음, ...로 가변 인자 설정 { va_list ap; // 가변 인자 목록 int i = 0; va_start(ap, types); // types 문자열에서 문자 개수를 구해서 가변 인자 포인터 설정로 va_start에 type의 주소를(크기가아닌) 전달하고 있습니다. 또 위에 설명에서보면
// types 문자열에서 문자 개수를 구해서 가변 인자 포인터 설정
라고 되어있는데 위 주석이 맞다면 printValues함수에서 인자를 char*가아닌 char type[]로 전달받고 va_start(ap,strlen(type))으로 해줘야하는게 아닌가해서요. 늘 감사드립니다.
인자에 char*냐 char[]이냐는 오래된 논쟁입니다. C 언어 표준에 대해 이해하면 논쟁할 필요가 없다는 아쉬움이 있습니다.
char[]로 되어 있으면 C 언어 컴파일러는 포인터로 변환해버립니다. 정확히는 첫 번째 원소의 포인터로 변환합니다.
int getline(char line[], int max)이나
int getline(char *line, int max)은 둘 다 같습니다.
getline 함수가 char line[]으로 선언되어 있어도 다음과 같이 두 가지 호출이 모두 가능합니다.
char line[100]; getline(line, 100);
char line[100]; getline(&line[0], 100);
표현식에서 배열 이름을 사용하면 컴파일러는 포인터로 변환합니다.
char[]이나 char*이나 둘 다 첨자 연산자 []를 쓸 수 있습니다.
다음을 기억하세요.
함수가 인자로 배열을 받는 척할 수 있습니다. char[]로 쓰면 됩니다. 그러나 배열의 내용을 수정하면 호출자에서도 수정됩니다. 포인터니까요.
배열은 항상 함수에 포인터로 전달됩니다. 따라서 함수가 포인터를 받을 수 있다고 선언하고 있다는 사실만 기억하고 있으면 됩니다.
포인터이니 strlen으로 길이를 알 수 없습니다. strlen으로 길이를 구하고 싶다면 항상 해당 포인터는 문자 배열이고 널(\0)로 끝난다는 것을 보장해야 합니다.
가변 인자 함수 예제에서는 형식 인자이고, 항상 널로 끝나는 문자 배열을 받는 것이니 문제가 없습니다.
C++, 자바, C# 같은 언어들은 문자열 개념이 있습니다. string 타입이 있습니다. C 언어는 string 타입이 없습니다. 문자열의 개념이 없습니다. 대신에 char 문자를 나열한 char[] 문자 배열이 문자열의 자리를 대신할 뿐입니다. char[]에는 문자 배열의 크기를 관리하는 방법이 없습니다. 널로 끝난다는 사실 하나만 알고 있을 뿐입니다. 따라서 별도로 크기를 관리하는 게 필수입니다(동적 할당의 경우).
string 타입은 보통 여러 가지가 있고, 길이를 직접 관리합니다. 예를 들어
struct string
{
int _length;
char* real_string;
}
같은 형태로 되어 있고, _length 같은 멤버로 문자열의 길이를 직접 관리하는 것입니다.
C 언어에서 'a'는 1바이트를 차지하지만, 자바에서 "a"는 8바이트 이상을 차지합니다.('a'와 "a"로 구분했습니다.)
자바에서
String str = "hello";
hello의 길이를 구하면 5가 출력되지만, 차지하는 실제 메모리는 5*8 = 40 바이트 이상입니다(자바 버전에 따라 크기가 달라집니다).
보통의 고급 언어는 문자열 개념이 있고, 매우 편리한 기능을 제공하지만, 메모리를 많이 사용합니다.
자바는 1문자에 보통 8배 정도의 메모리 공간이 필요합니다.
유전자 염기서열이나 빅데이터처럼 1TB 텍스트 데이터를 읽어서 처리한다면, 전부를 메모리에 로딩하려 할 때 C 언어는 1TB면 되고, 자바는 최소 8TB의 메모리가 필요하다는 뜻입니다.(대신 자바의 문자열은 UTF-8 인코딩을 처리하고, 다국어를 지원합니다).
각기 장단점이 있다는 뜻입니다. 불편하지만 빠르고, 편하지만 느리고.
자바8의 String 소스 코드를 보면
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/String.java
111번째 줄에 String 클래스를 선언하고,
114번 줄에
private final char value[];
실제 문자열을 담을 char 배열을 선언합니다. 자바는 문자열이 불변이므로 final이라고 선언합니다.117번 줄에
private int hash; // Default to 0
문자열에 해단 해시 값을 저장하는 hash가 int로 선언되어 있습니다. int가 4바이트이니 자바의 문자열은 1문자만 남겨도 최소 4바이트 + 1문자 공간을 차지합니다.120번 줄에
private static final long serialVersionUID = -6849794470754667710L;
이러한 long 변수도 저장되어 있습니다.자바는 이런식으로 문자열을 위한 편리한 기능을 위해 실제로는 내부에 모든 것을 미리 구현해둔 것입니다.(C 언어로 구현하면 됩니다. 그러나 성능이 목적이므로 대다수는 순수 C 언어의 문자열 처리를 사용합니다. string.h 구현)
그래서 자바 문자열은 숨만 쉬어도 메모리를 많이 차지합니다. ^^;
C 언어는 시스템 프로그래밍에 최적화되어 있고, 성능이 최우선입니다.
C vs Java처럼 누가 더 빠르냐는 논쟁은 그래서 의미가 없습니다. 용도에 맞게 쓰는 게 좋습니다.
ps. 흔한 농담입니다. 자바는 숨만 쉬어도 메모리를 먹는다고...;;;
대신 "객체지향적으로 부자가 되는 방법이 상속(inheritance)이야"라고 합니다. 상속 덕분에 자바 프로그래머는 출발선이 다릅니다. 금수저랄까요.