memset보다 bzero를 사용하는 이유는 무엇입니까?


156

시스템 프로그래밍 클래스에서이 전 학기를 수강했습니다. C에서 기본 클라이언트 / 서버를 구현해야했습니다. sock_addr_in, 또는 버퍼 버퍼 (클라이언트와 서버간에 데이터를주고받는 데 사용 된) 와 같은 구조체를 초기화 할 때 교수 초기화 만하지 bzero말라고 지시 memset했습니다. 그는 왜 그런지 설명하지 않았으며, 이것에 대한 정당한 이유가 있는지 궁금합니다.

나는 여기를 참조하십시오 : http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown 그것은 bzero단지 제로 메모리가 될 것이라는 사실 때문에 더 효율적이므로, 그렇지 않습니다 추가 점검을 memset수행해야합니다. 그래도 memset메모리를 제로화 하는 데 절대 사용하지 않는 이유는 아닙니다 .

bzero는 더 이상 사용되지 않으며 표준 C 함수가 아닙니다. 매뉴얼에 따르면 이러한 이유로 memset선호 bzero됩니다. 그렇다면 왜 아직도 사용 bzero하고 memset싶습니까? 효율성 향상을위한 것입니까, 아니면 더 많은 것입니까? 마찬가지로 새로운 프로그램에 대해 실제로 선호되는 옵션이되는 것 memset이상의 장점은 무엇 bzero입니까?


28
"왜 memset보다 bzero를 사용합니까?" - 하지마 Memset은 표준이며 bzero는 그렇지 않습니다.

30
bzero는 BSDism ()입니다. memset ()은 ansi-c입니다. 요즘, bzero ()는 아마도 매크로로 구현 될 것입니다. 교수님에게 면도를하고 책을 읽어달라고 부탁하십시오. 효율성 은 가짜 주장입니다. syscall 또는 context-switch는 버스 속도로 실행되는 버퍼를 통과하는 1 만 개의 클럭 틱을 쉽게 소비 할 수 있습니다. 네트워크 프로그램을 최적화하려면 : 더 큰 청크를 읽거나 쓰는 방식으로 syscall 수를 최소화하십시오
wildplasser

7
memset"조금 더 많은 검사가 진행됨"으로 인해 약간 덜 효율적 이라는 아이디어 는 분명히 조기 최적화의 경우입니다. 암호. bzero사용되지 않는 충분한 이유입니다.
dasblinkenlight 2016 년

4
종종 이니셜 라이저`= {0}`을 추가하고 함수를 전혀 호출하지 않을 수 있습니다. C는 세기 초경에 지역 변수에 대한 사전 선언이 필요하지 않을 때 쉬워졌습니다. 일부 정말 오래된 paperware하지만, 여전히 이전 세기에 붙어 깊은이다.
MSalters

1
@ SSAnne 아니오, 그러나 아래 답변 중 하나에서 언급 한 것처럼 영향을받는 과정에 대한 권장 책에서 시작되었을 가능성이 큽니다. stackoverflow.com/a/17097072/1428743
PseudoPsyche

답변:


152

bzero이상 을 선호 할 이유가 없습니다 memset.

memset반면 표준 C의 함수이다 bzero는 C 표준 기능 적이있다. 이론적 근거는 아마도 함수를 사용하여 정확히 동일한 기능을 달성 할 수 있기 때문일 것입니다 memset.

이제 효율성과 관련하여 컴파일러 는 상수 가 감지 될 때 특정 구현으로 전환 gcc하는 내장 구현을 사용 합니다. 내장 기능이 비활성화 된 경우 와 동일합니다 .memset0glibc


감사. 이것은 말이됩니다. 나는 memset이 경우에 항상 사용해야한다고 확신 했지만, 왜 우리가 그것을 사용하지 않는지 혼란 스러웠습니다. 의견을 명확히하고 다시 한 번 감사드립니다.
PseudoPsyche 2016 년

1
깨진 bzero구현에 많은 문제가있었습니다 . 정렬되지 않은 배열에서는 제공된 길이를 오버 슛하고 약간 더 많은 바이트를 0으로 만들었습니다. 으로 전환 한 후 이러한 문제가 발생하지 않았습니다 memset.
rustyx

memset_s컴파일러가 보안 관련 목적 (예 : 민감한 부분이 포함 된 메모리 영역을 비우는 등)을 위해 "스크럽 (scrub)"메모리 호출을 조용히 최적화하지 않으려면 어떤 것을 사용해야하는지 잊지 마십시오. 일반 텍스트 비밀번호와 같은 정보).
Christopher Schultz

69

W. Richard Stevens의 UNIX 네트워크 프로그래밍 을 사용했거나 교사의 영향을 받았다고 생각합니다 . 그는 최신 버전에서도 bzero자주 사용하지 memset않습니다. 이 책은 매우 인기가 많기 때문에 네트워크 프로그래밍의 관용구가 된 것 같습니다.

더 이상 사용되지 않으며 이식성이 줄어들 memset기 때문에 간단하게 고수 할 것 bzero입니다. 나는 당신이 하나를 다른 것보다 사용함으로써 실질적인 이익을 볼 것이라고 의심합니다.


4
당신은 맞을 것입니다. 우리는이 과정에 필요한 교과서를 필요로하지 않았지만, 강의 계획서를 다시 확인했고 유닉스 네트워크 프로그래밍 은 실제로 선택적인 자료로 나열되어 있습니다. 감사.
PseudoPsyche 2016 년

9
실제로 그것보다 더 나쁩니다. POSIX.1-2001에서 폐기되었으며 POSIX.1-2008에서 제거 되었습니다.
paxdiablo

9
W. Richard Stevens 의 UNIX 네트워크 프로그래밍 제 3 판 8 페이지 인용 - 실제로 TCPv3의 저자는 두 번째와 세 번째 인수를 첫 번째 인쇄에서 10 번씩 memset으로 바꾸는 실수를했습니다. AC 컴파일러는 두 가지 발생이 동일하기 때문에이 오류를 포착 할 수 없습니다. 오류입니다. 함수 프로토 타입을 사용하는 경우 두 인수를 bzero로 교체하면 항상 C 컴파일러가이를 포착하므로 bzero를 사용하여 피할 수 있습니다. 그러나 paxdiablo가 지적했듯이 bzero는 더 이상 사용되지 않습니다.
Aaron Newton

@AaronNewton, Michael의 답변에 추가해야합니다 .
Synetech

52

내가 생각하는 장점 중 하나 bzero()이상이 memset()제로에 메모리를 설정 만들어지고 실수의 감소 가능성이 있다는 것이다.

한 번 이상 다음과 같은 버그가 발생했습니다.

memset(someobject, size_of_object, 0);    // clear object

컴파일러는 불만을 제기하지 않으며 (어쩌면 일부 컴파일러에서 경고 수준을 높이면 일부 메모리가 지워질 수 있음) 영향을받습니다. 이것은 객체를 휴지통에 버리지 않기 때문에 그냥 내버려두기 때문에 버그가 분명하게 나타나지 않을 가능성이 있습니다.

bzero()표준이 아니라는 사실 은 사소한 자극입니다. (FWIW, 프로그램에서 대부분의 함수 호출이 표준이 아닌 경우 놀라지 않을 것입니다. 사실 그러한 함수를 작성하는 것이 일종의 일입니다).

또 다른 답변에 대한 언급에서 Aaron Newton은 Stevens 등의 1.2 절 (강조 추가)에 의해 Unix Network Programming, Volume 1, 3rd Edition에서 다음을 인용했습니다.

bzeroANSI C 함수가 아닙니다. 초기 Berkely 네트워킹 코드에서 파생되었습니다. 그럼에도 불구하고, 우리는 ANSI C memset함수 대신 텍스트 전체에서 그것을 사용합니다 . 왜냐하면 (세 bzero개의 인수로)보다 memset( 두 개의 인수로) 기억 하기 가 쉽기 때문 입니다 . 소켓 API를 지원하는 거의 모든 벤더는 또한을 제공 bzero하며, 그렇지 않은 경우 unp.h헤더에 매크로 정의를 제공합니다 .

실제로, TCPv3의 저자 [TCP / IP Illustrated, Volume 3-Stevens 1996]는 memset첫 번째 인쇄에서 두 번째와 세 번째 인수를 10 번 으로 바꾸는 실수를 했습니다 . 두 인수가 모두 같은 유형이므로 AC 컴파일러는이 오류를 포착 할 수 없습니다. 실제로 두 번째 인수는 일반 int적이고 세 번째 인수는 size_t일반적으로 unsigned int이지만 다른 유형의 인수에는 각각 0과 16으로 지정된 값을 memset여전히 사용할 수 있습니다. 소켓 함수 중 일부는 실제로 인터넷 소켓 주소 구조의 마지막 8 바이트를 0으로 설정해야합니다. 그럼에도 불구하고 오류이며이를 사용하여 피할 수 있습니다 bzerobzero함수 프로토 타입을 사용하는 경우 두 인수를 서로 바꾸면 항상 C 컴파일러에서 잡을 수 있기 때문 입니다.

또한 대부분의 호출 memset()은 메모리를 0으로 하는 것이라고 생각 하므로 해당 사용 사례에 맞는 API를 사용하지 않겠습니까?

가능한 단점 bzero()은 컴파일러가 memcpy()표준이기 때문에 최적화 할 가능성이 높기 때문에이를 인식하도록 작성 될 수 있다는 것입니다. 그러나 올바른 코드는 여전히 최적화 된 잘못된 코드보다 낫습니다. 대부분 bzero()bzero()경우을 사용 하면 프로그램 성능에 눈에 띄는 영향을 미치지 않으며으로 확장되는 매크로 또는 인라인 함수일 수 있습니다 memcpy().


그렇습니다. 교실 환경에서 일할 때 이것이 학생들에게 혼란을 줄 이도록 추론 할 수 있다고 생각합니다. 그러나 이것이 교수님의 경우라고 생각하지 않습니다. 그는 매우 큰 RTFM 교사였습니다. 매뉴얼로 대답 할 수있는 질문이있는 경우, 그는 수업 시간에 프로젝터의 매뉴얼 페이지를 가져 와서 보여줍니다. 그는 매뉴얼을 읽고 대부분의 질문에 대답해야한다는 모든 사람들의 마음에 깊이 빠져 들었습니다. 다른 교수 들과는 달리 이것에 감사합니다.
PseudoPsyche 2016 년

5
나는 이것이 교실 밖에서도 할 수있는 논쟁이라고 생각합니다. 제작 코드 에서이 버그를 보았습니다. 그것은 쉬운 실수라고 생각합니다. 또한 대부분의 memset()호출은 단순히 메모리 블록을 제로화하는 것입니다 bzero(). bzero()어쨌든 'b'는 무엇을 의미 합니까?
Michael Burr

7
+1. 즉 memset그것은 특히 오류가 발생하기 쉬운 IMO한다 "BUFFER_SIZE, 버퍼"의 공통 매개 변수 순서를 위반합니다.
jamesdlin

파스칼에서는 "fillchar"라고 부르는 것을 피하고 문자를 취합니다. 대부분의 C / C ++ 컴파일러는 그 중 하나를 선택합니다. 컴파일러가 왜 "바이트가 예상되는 곳에 32/64 비트 포인터를 전달하고있다"고 말하지 않고 컴파일러 오류를 확실하게하게되는 이유가 궁금합니다.
Móż

1
@Gewure 두 번째 및 세 번째 인수의 순서가 잘못되었습니다. 인용 된 함수 호출은 정확히 아무 것도
Ichthyo

4

bzero 대 memset 인수에 대해 언급하고 싶었습니다. ltrace를 설치 한 후 후드에서 수행하는 작업을 비교하십시오. libc6 (2.19-0ubuntu6.6)을 사용하는 Linux에서 호출은을 통해 정확히 동일합니다 ltrace ./test123.

long m[] = {0}; // generates a call to memset(0x7fffefa28238, '\0', 8)
int* p;
bzero(&p, 4);   // generates a call to memset(0x7fffefa28230, '\0', 4)

나는 libc깊은 창 이나 많은 커널 / 시스템 콜 인터페이스에서 작업하지 않는 한 걱정할 필요 가 없다고 들었 습니다. 내가 걱정해야 할 것은 호출이 버퍼 제로화 요구 사항을 충족한다는 것입니다. 다른 사람들은 어느 것이 다른 것보다 선호되는지 언급 했으므로 여기서 멈 춥니 다.


이것은 GCC의 일부 버전에서 코드를 memset(ptr, 0, n)보고 bzero(ptr, n)인라인 코드로 변환 할 수 없기 때문에 발생 합니다.
zwol

@zwol 실제로는 매크로입니다.
SS Anne

1
내 컴퓨터의 @SSAnne gcc 9.3은 시스템 헤더의 매크로의 도움 없이이 변환 자체를 수행합니다. extern void bzero(void *, size_t); void clear(void *p, size_t n) { bzero(p, n); }에 대한 호출을 생성합니다 memset. (포함 stddef.h에 대한 size_t방해 할 수있는 다른 것없이.)
zwol

4

당신은 아마 사용 bzero사실은 표준 C 아니다, 그것은 POSIX 일이었다.

그리고 단어 "했다"참고 - 그것이 되지 POSIX.1-2001과 제거 당신은 더 나은 표준 C 함수를 사용하여 길 이죠, 그래서 memset 함수에 복종에 POSIX.1-2008에.


표준 C의 의미는 무엇입니까? 표준 C 라이브러리에서 찾을 수 없다는 것을 의미합니까?
Koray Tugay

@Koray, 표준 C는 ISO 표준을 의미하며 그렇습니다 bzero.
paxdiablo

아니, 난 당신이 어떤 표준에 의해 무슨 뜻인지 모르겠어요. ISO 표준이 표준 C 라이브러리를 의미합니까? 언어와 함께 제공됩니까? 우리가 알고있는 최소한의 도서관이 있을까요?
Koray Tugay

2
@Koray, ISO는 C 표준, 현재 C11, 이전 C99 및 C89를 담당하는 표준 조직입니다. 그들은 C로 간주되기 위해 구현이 따라야하는 규칙을 제시합니다. 따라서 표준이 구현이 memset을 제공해야한다고 말한다면 그것은 당신을 위해있을 것입니다. 그렇지 않으면 C가 아닙니다.
paxdiablo

2

memset 함수 함수, 제 2 인수가 인 int세 번째 인자 인 size_t,

void *memset(void *s, int c, size_t n);

이것은 일반적으로 unsigned int이지만 0 and 16두 번째 및 세 번째 인수에 대한 값이 각각 16 및 0과 같은 잘못된 순서로 입력되면 memset에 대한 호출은 여전히 ​​작동 할 수 있지만 아무것도하지 않습니다. 초기화 할 바이트 수는로 지정되어 있기 때문 0입니다.

void bzero(void *s, size_t n)

함수 프로토 타입을 사용하는 경우 두 인수를 bzero로 바꾸는 것은 항상 C 컴파일러에 의해 잡히므로 bzero를 사용하면 이러한 오류를 피할 수 있습니다.


1
호출을 "이 크기에 대해이 메모리를이 값으로 설정"이라고 생각하거나 프로토 타입을 제공하는 IDE가 있거나 자신이 무엇을 알고 있는지 알고있는 경우 memset을 사용하면 이러한 오류를 피할 수 있습니다. :-)
paxdiablo 1

동의하지만이 기능은 인텔리전트 IDE를 지원할 수 없을 때 만들어졌습니다.
havish

2

한마디로 : memset 더 많은 어셈블리 작업이 필요합니다 bzero.

이것은 소스입니다 : http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown


예, 이것이 OP에서 언급 한 것 중 하나입니다. 나는 실제로 그 정확한 페이지에 연결했습니다. 일부 컴파일러 최적화로 인해 실제로 큰 차이가없는 것으로 나타났습니다. 자세한 내용은 ouah의 수락 된 답변을 참조하십시오.
PseudoPsyche

6
이것은 단지 memset의 하나의 쓰레기 구현이 느리다는 것을 보여줍니다. MacOS X 및 일부 다른 시스템에서 memset은 사용중인 프로세서에 따라 부팅시 설정된 코드를 사용하고 벡터 레지스터를 최대한 활용하며, 큰 크기의 경우 프리 페치 명령어를 사용하여 마지막 비트를 얻기 위해 영리한 방법으로 사용합니다 속도.
gnasher729

명령이 적다고해서 실행 속도가 빠르지는 않습니다. 사실 최적화는 종종 인해 루프 언 롤링, 기능 인라인, 루프 정렬 ... 어떤 점잖은 최적화 된 코드를보고 명령의 바이너리 크기와 수를 증가하고 당신은 종종 훨씬 더 엿 구현에 비해 지침이 나타납니다
phuclv

2

원하는 방식으로 사용하십시오. :-)

#ifndef bzero
#define bzero(d,n) memset((d),0,(n))
#endif

참고 :

  1. 원본 bzero은 아무것도 반환하지 않고 memsetvoid 포인터 ( d)를 반환합니다 . 이것은 정의에서 void에 typecast를 추가하여 해결할 수 있습니다.
  2. #ifndef bzero원래 기능이 존재하더라도 숨길 수는 없습니다. 매크로가 있는지 테스트합니다. 이것은 많은 혼란을 야기 할 수 있습니다.
  3. 매크로에 대한 함수 포인터를 만드는 것은 불가능합니다. bzerovia 함수 포인터를 사용하면 작동하지 않습니다.

1
@Leeor 문제가 무엇입니까? 매크로에 대한 일반적인 반감? 아니면이 매크로가 함수와 혼동 될 수 있다는 사실을 싫어합니까?
Palec

1
@Palec, 후자. 재정의를 매크로로 숨기면 많은 혼란이 생길 ​​수 있습니다. 이 코드를 사용하는 다른 프로그래머는 자신이 한 가지를 사용하고 있다고 생각하고 모르고 다른 것을 사용해야합니다. 그것은 시한 폭탄입니다.
Leeor

1
다른 생각을 한 후에 나는 이것이 실제로 나쁜 해결책이라는 데 동의합니다. 무엇보다도 기술적 인 이유를 발견했습니다. bzero비아 함수 포인터를 사용할 때 작동하지 않습니다.
Palec

매크로가 아닌 다른 매크로를 호출해야합니다 bzero. 이것은 곤란하다.
Dan Bechard

-2

memset은 3 개의 매개 변수를 사용하고, bzero는 메모리에서 2를 사용하고, 추가 매개 변수는 4 바이트를 더 필요로하고 대부분의 경우 모든 것을 0으로 설정하는 데 사용됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.